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/GrCoverageSetOpXP.h"
9#include "GrCaps.h"
10#include "GrColor.h"
11#include "GrPipeline.h"
12#include "GrProcessor.h"
13#include "GrRenderTargetContext.h"
14#include "glsl/GrGLSLBlend.h"
15#include "glsl/GrGLSLFragmentShaderBuilder.h"
16#include "glsl/GrGLSLUniformHandler.h"
17#include "glsl/GrGLSLXferProcessor.h"
18
19class CoverageSetOpXP : public GrXferProcessor {
20public:
21    CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage)
22            : INHERITED(kCoverageSetOpXP_ClassID)
23            , fRegionOp(regionOp)
24            , fInvertCoverage(invertCoverage) {}
25
26    const char* name() const override { return "Coverage Set Op"; }
27
28    GrGLSLXferProcessor* createGLSLInstance() const override;
29
30    bool invertCoverage() const { return fInvertCoverage; }
31
32private:
33
34    void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
35
36    void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override;
37
38    bool onIsEqual(const GrXferProcessor& xpBase) const override {
39        const CoverageSetOpXP& xp = xpBase.cast<CoverageSetOpXP>();
40        return (fRegionOp == xp.fRegionOp &&
41                fInvertCoverage == xp.fInvertCoverage);
42    }
43
44    SkRegion::Op fRegionOp;
45    bool         fInvertCoverage;
46
47    typedef GrXferProcessor INHERITED;
48};
49
50///////////////////////////////////////////////////////////////////////////////
51
52class GLCoverageSetOpXP : public GrGLSLXferProcessor {
53public:
54    GLCoverageSetOpXP(const GrProcessor&) {}
55
56    ~GLCoverageSetOpXP() override {}
57
58    static void GenKey(const GrProcessor& processor, const GrShaderCaps& caps,
59                       GrProcessorKeyBuilder* b) {
60        const CoverageSetOpXP& xp = processor.cast<CoverageSetOpXP>();
61        uint32_t key = xp.invertCoverage() ?  0x0 : 0x1;
62        b->add32(key);
63    }
64
65private:
66    void emitOutputsForBlendState(const EmitArgs& args) override {
67        const CoverageSetOpXP& xp = args.fXP.cast<CoverageSetOpXP>();
68        GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
69
70        if (xp.invertCoverage()) {
71            fragBuilder->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage);
72        } else {
73            fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
74        }
75    }
76
77    void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
78
79    typedef GrGLSLXferProcessor INHERITED;
80};
81
82///////////////////////////////////////////////////////////////////////////////
83
84void CoverageSetOpXP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
85                                            GrProcessorKeyBuilder* b) const {
86    GLCoverageSetOpXP::GenKey(*this, caps, b);
87}
88
89GrGLSLXferProcessor* CoverageSetOpXP::createGLSLInstance() const {
90    return new GLCoverageSetOpXP(*this);
91}
92
93void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const {
94    switch (fRegionOp) {
95        case SkRegion::kReplace_Op:
96            blendInfo->fSrcBlend = kOne_GrBlendCoeff;
97            blendInfo->fDstBlend = kZero_GrBlendCoeff;
98            break;
99        case SkRegion::kIntersect_Op:
100            blendInfo->fSrcBlend = kDC_GrBlendCoeff;
101            blendInfo->fDstBlend = kZero_GrBlendCoeff;
102            break;
103        case SkRegion::kUnion_Op:
104            blendInfo->fSrcBlend = kOne_GrBlendCoeff;
105            blendInfo->fDstBlend = kISC_GrBlendCoeff;
106            break;
107        case SkRegion::kXOR_Op:
108            blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
109            blendInfo->fDstBlend = kISC_GrBlendCoeff;
110            break;
111        case SkRegion::kDifference_Op:
112            blendInfo->fSrcBlend = kZero_GrBlendCoeff;
113            blendInfo->fDstBlend = kISC_GrBlendCoeff;
114            break;
115        case SkRegion::kReverseDifference_Op:
116            blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
117            blendInfo->fDstBlend = kZero_GrBlendCoeff;
118            break;
119    }
120    blendInfo->fBlendConstant = 0;
121}
122
123///////////////////////////////////////////////////////////////////////////////
124
125constexpr GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp,
126                                                             bool invertCoverage)
127        : fRegionOp(regionOp), fInvertCoverage(invertCoverage) {}
128
129const GrXPFactory* GrCoverageSetOpXPFactory::Get(SkRegion::Op regionOp, bool invertCoverage) {
130    // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are
131    // null.
132#ifdef SK_BUILD_FOR_WIN
133#define _CONSTEXPR_
134#else
135#define _CONSTEXPR_ constexpr
136#endif
137    switch (regionOp) {
138        case SkRegion::kReplace_Op: {
139            if (invertCoverage) {
140                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gReplaceCDXPFI(
141                        SkRegion::kReplace_Op, true);
142                return &gReplaceCDXPFI;
143            } else {
144                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gReplaceCDXPF(
145                        SkRegion::kReplace_Op, false);
146                return &gReplaceCDXPF;
147            }
148        }
149        case SkRegion::kIntersect_Op: {
150            if (invertCoverage) {
151                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gIntersectCDXPFI(
152                        SkRegion::kIntersect_Op, true);
153                return &gIntersectCDXPFI;
154            } else {
155                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gIntersectCDXPF(
156                        SkRegion::kIntersect_Op, false);
157                return &gIntersectCDXPF;
158            }
159        }
160        case SkRegion::kUnion_Op: {
161            if (invertCoverage) {
162                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gUnionCDXPFI(SkRegion::kUnion_Op,
163                                                                               true);
164                return &gUnionCDXPFI;
165            } else {
166                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gUnionCDXPF(SkRegion::kUnion_Op,
167                                                                              false);
168                return &gUnionCDXPF;
169            }
170        }
171        case SkRegion::kXOR_Op: {
172            if (invertCoverage) {
173                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gXORCDXPFI(SkRegion::kXOR_Op,
174                                                                             true);
175                return &gXORCDXPFI;
176            } else {
177                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gXORCDXPF(SkRegion::kXOR_Op,
178                                                                            false);
179                return &gXORCDXPF;
180            }
181        }
182        case SkRegion::kDifference_Op: {
183            if (invertCoverage) {
184                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gDifferenceCDXPFI(
185                        SkRegion::kDifference_Op, true);
186                return &gDifferenceCDXPFI;
187            } else {
188                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gDifferenceCDXPF(
189                        SkRegion::kDifference_Op, false);
190                return &gDifferenceCDXPF;
191            }
192        }
193        case SkRegion::kReverseDifference_Op: {
194            if (invertCoverage) {
195                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gRevDiffCDXPFI(
196                        SkRegion::kReverseDifference_Op, true);
197                return &gRevDiffCDXPFI;
198            } else {
199                static _CONSTEXPR_ const GrCoverageSetOpXPFactory gRevDiffCDXPF(
200                        SkRegion::kReverseDifference_Op, false);
201                return &gRevDiffCDXPF;
202            }
203        }
204    }
205#undef _CONSTEXPR_
206    SK_ABORT("Unknown region op.");
207    return nullptr;
208}
209
210sk_sp<const GrXferProcessor> GrCoverageSetOpXPFactory::makeXferProcessor(
211        const GrProcessorAnalysisColor&,
212        GrProcessorAnalysisCoverage,
213        bool hasMixedSamples,
214        const GrCaps& caps,
215        GrPixelConfigIsClamped dstIsClamped) const {
216    // We don't support inverting coverage with mixed samples. We don't expect to ever want this in
217    // the future, however we could at some point make this work using an inverted coverage
218    // modulation table. Note that an inverted table still won't work if there are coverage procs.
219    if (fInvertCoverage && hasMixedSamples) {
220        SkASSERT(false);
221        return nullptr;
222    }
223
224    return sk_sp<GrXferProcessor>(new CoverageSetOpXP(fRegionOp, fInvertCoverage));
225}
226
227GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory);
228
229#if GR_TEST_UTILS
230const GrXPFactory* GrCoverageSetOpXPFactory::TestGet(GrProcessorTestData* d) {
231    SkRegion::Op regionOp = SkRegion::Op(d->fRandom->nextULessThan(SkRegion::kLastOp + 1));
232    bool isMixedSamples = GrFSAAType::kMixedSamples == d->fRenderTargetContext->fsaaType();
233    bool invertCoverage = !isMixedSamples && d->fRandom->nextBool();
234    return GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage);
235}
236#endif
237