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/GrCoverageSetOpXP.h"
9
10#include "src/gpu/GrCaps.h"
11#include "src/gpu/GrColor.h"
12#include "src/gpu/GrPipeline.h"
13#include "src/gpu/GrXferProcessor.h"
14#include "src/gpu/glsl/GrGLSLBlend.h"
15#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
16#include "src/gpu/glsl/GrGLSLUniformHandler.h"
17
18class CoverageSetOpXP : public GrXferProcessor {
19public:
20    CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage)
21            : INHERITED(kCoverageSetOpXP_ClassID)
22            , fRegionOp(regionOp)
23            , fInvertCoverage(invertCoverage) {}
24
25    const char* name() const override { return "Coverage Set Op"; }
26
27    SkString getShaderDfxInfo() const override;
28
29    std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
30
31private:
32    void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
33
34    void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override;
35
36    bool onIsEqual(const GrXferProcessor& xpBase) const override {
37        const CoverageSetOpXP& xp = xpBase.cast<CoverageSetOpXP>();
38        return (fRegionOp == xp.fRegionOp &&
39                fInvertCoverage == xp.fInvertCoverage);
40    }
41
42    SkRegion::Op fRegionOp;
43    bool         fInvertCoverage;
44
45    using INHERITED = GrXferProcessor;
46};
47
48SkString CoverageSetOpXP::getShaderDfxInfo() const
49{
50    SkString format;
51    format.printf("ShaderDfx_CoverageSetOpXP_%d", fInvertCoverage);
52    return format;
53}
54
55void CoverageSetOpXP::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
56    b->addBool(fInvertCoverage, "invert coverage");
57}
58
59std::unique_ptr<GrXferProcessor::ProgramImpl> CoverageSetOpXP::makeProgramImpl() const {
60    class Impl : public ProgramImpl {
61    private:
62        void emitOutputsForBlendState(const EmitArgs& args) override {
63            const CoverageSetOpXP& xp = args.fXP.cast<CoverageSetOpXP>();
64            GrGLSLXPFragmentBuilder* fb = args.fXPFragBuilder;
65            if (xp.fInvertCoverage) {
66                fb->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage);
67            } else {
68                fb->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
69            }
70        }
71    };
72    return std::make_unique<Impl>();
73}
74
75void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const {
76    switch (fRegionOp) {
77        case SkRegion::kReplace_Op:
78            blendInfo->fSrcBlend = kOne_GrBlendCoeff;
79            blendInfo->fDstBlend = kZero_GrBlendCoeff;
80            break;
81        case SkRegion::kIntersect_Op:
82            blendInfo->fSrcBlend = kDC_GrBlendCoeff;
83            blendInfo->fDstBlend = kZero_GrBlendCoeff;
84            break;
85        case SkRegion::kUnion_Op:
86            blendInfo->fSrcBlend = kOne_GrBlendCoeff;
87            blendInfo->fDstBlend = kISC_GrBlendCoeff;
88            break;
89        case SkRegion::kXOR_Op:
90            blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
91            blendInfo->fDstBlend = kISC_GrBlendCoeff;
92            break;
93        case SkRegion::kDifference_Op:
94            blendInfo->fSrcBlend = kZero_GrBlendCoeff;
95            blendInfo->fDstBlend = kISC_GrBlendCoeff;
96            break;
97        case SkRegion::kReverseDifference_Op:
98            blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
99            blendInfo->fDstBlend = kZero_GrBlendCoeff;
100            break;
101    }
102    blendInfo->fBlendConstant = SK_PMColor4fTRANSPARENT;
103}
104
105///////////////////////////////////////////////////////////////////////////////
106
107constexpr GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp,
108                                                             bool invertCoverage)
109        : fRegionOp(regionOp), fInvertCoverage(invertCoverage) {}
110
111const GrXPFactory* GrCoverageSetOpXPFactory::Get(SkRegion::Op regionOp, bool invertCoverage) {
112    switch (regionOp) {
113        case SkRegion::kReplace_Op: {
114            if (invertCoverage) {
115                static constexpr const GrCoverageSetOpXPFactory gReplaceCDXPFI(
116                        SkRegion::kReplace_Op, true);
117                return &gReplaceCDXPFI;
118            } else {
119                static constexpr const GrCoverageSetOpXPFactory gReplaceCDXPF(SkRegion::kReplace_Op,
120                                                                              false);
121                return &gReplaceCDXPF;
122            }
123        }
124        case SkRegion::kIntersect_Op: {
125            if (invertCoverage) {
126                static constexpr const GrCoverageSetOpXPFactory gIntersectCDXPFI(
127                        SkRegion::kIntersect_Op, true);
128                return &gIntersectCDXPFI;
129            } else {
130                static constexpr const GrCoverageSetOpXPFactory gIntersectCDXPF(
131                        SkRegion::kIntersect_Op, false);
132                return &gIntersectCDXPF;
133            }
134        }
135        case SkRegion::kUnion_Op: {
136            if (invertCoverage) {
137                static constexpr const GrCoverageSetOpXPFactory gUnionCDXPFI(SkRegion::kUnion_Op,
138                                                                             true);
139                return &gUnionCDXPFI;
140            } else {
141                static constexpr const GrCoverageSetOpXPFactory gUnionCDXPF(SkRegion::kUnion_Op,
142                                                                            false);
143                return &gUnionCDXPF;
144            }
145        }
146        case SkRegion::kXOR_Op: {
147            if (invertCoverage) {
148                static constexpr const GrCoverageSetOpXPFactory gXORCDXPFI(SkRegion::kXOR_Op, true);
149                return &gXORCDXPFI;
150            } else {
151                static constexpr const GrCoverageSetOpXPFactory gXORCDXPF(SkRegion::kXOR_Op, false);
152                return &gXORCDXPF;
153            }
154        }
155        case SkRegion::kDifference_Op: {
156            if (invertCoverage) {
157                static constexpr const GrCoverageSetOpXPFactory gDifferenceCDXPFI(
158                        SkRegion::kDifference_Op, true);
159                return &gDifferenceCDXPFI;
160            } else {
161                static constexpr const GrCoverageSetOpXPFactory gDifferenceCDXPF(
162                        SkRegion::kDifference_Op, false);
163                return &gDifferenceCDXPF;
164            }
165        }
166        case SkRegion::kReverseDifference_Op: {
167            if (invertCoverage) {
168                static constexpr const GrCoverageSetOpXPFactory gRevDiffCDXPFI(
169                        SkRegion::kReverseDifference_Op, true);
170                return &gRevDiffCDXPFI;
171            } else {
172                static constexpr const GrCoverageSetOpXPFactory gRevDiffCDXPF(
173                        SkRegion::kReverseDifference_Op, false);
174                return &gRevDiffCDXPF;
175            }
176        }
177    }
178    SK_ABORT("Unknown region op.");
179}
180
181sk_sp<const GrXferProcessor> GrCoverageSetOpXPFactory::makeXferProcessor(
182        const GrProcessorAnalysisColor&,
183        GrProcessorAnalysisCoverage,
184        const GrCaps& caps,
185        GrClampType) const {
186    return sk_sp<GrXferProcessor>(new CoverageSetOpXP(fRegionOp, fInvertCoverage));
187}
188
189GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory);
190
191#if GR_TEST_UTILS
192const GrXPFactory* GrCoverageSetOpXPFactory::TestGet(GrProcessorTestData* d) {
193    SkRegion::Op regionOp = SkRegion::Op(d->fRandom->nextULessThan(SkRegion::kLastOp + 1));
194    bool invertCoverage = d->fRandom->nextBool();
195    return GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage);
196}
197#endif
198