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 
19 class CoverageSetOpXP : public GrXferProcessor {
20 public:
CoverageSetOpXP(SkRegion::Op regionOp,bool invertCoverage)21     CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage)
22             : INHERITED(kCoverageSetOpXP_ClassID)
23             , fRegionOp(regionOp)
24             , fInvertCoverage(invertCoverage) {}
25 
name() const26     const char* name() const override { return "Coverage Set Op"; }
27 
28     GrGLSLXferProcessor* createGLSLInstance() const override;
29 
invertCoverage() const30     bool invertCoverage() const { return fInvertCoverage; }
31 
32 private:
33 
34     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
35 
36     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override;
37 
onIsEqual(const GrXferProcessor & xpBase) const38     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 
52 class GLCoverageSetOpXP : public GrGLSLXferProcessor {
53 public:
GLCoverageSetOpXP(const GrProcessor &)54     GLCoverageSetOpXP(const GrProcessor&) {}
55 
~GLCoverageSetOpXP()56     ~GLCoverageSetOpXP() override {}
57 
GenKey(const GrProcessor & processor,const GrShaderCaps & caps,GrProcessorKeyBuilder * b)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 
65 private:
emitOutputsForBlendState(const EmitArgs & args)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 
onSetData(const GrGLSLProgramDataManager &,const GrXferProcessor &)77     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
78 
79     typedef GrGLSLXferProcessor INHERITED;
80 };
81 
82 ///////////////////////////////////////////////////////////////////////////////
83 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const84 void CoverageSetOpXP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
85                                             GrProcessorKeyBuilder* b) const {
86     GLCoverageSetOpXP::GenKey(*this, caps, b);
87 }
88 
createGLSLInstance() const89 GrGLSLXferProcessor* CoverageSetOpXP::createGLSLInstance() const {
90     return new GLCoverageSetOpXP(*this);
91 }
92 
onGetBlendInfo(GrXferProcessor::BlendInfo * blendInfo) const93 void 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 
GrCoverageSetOpXPFactory(SkRegion::Op regionOp,bool invertCoverage)125 constexpr GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp,
126                                                              bool invertCoverage)
127         : fRegionOp(regionOp), fInvertCoverage(invertCoverage) {}
128 
Get(SkRegion::Op regionOp,bool invertCoverage)129 const 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 
makeXferProcessor(const GrProcessorAnalysisColor &,GrProcessorAnalysisCoverage,bool hasMixedSamples,const GrCaps & caps,GrPixelConfigIsClamped dstIsClamped) const210 sk_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 
227 GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory);
228 
229 #if GR_TEST_UTILS
TestGet(GrProcessorTestData * d)230 const 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