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