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 "GrDrawContext.h"
12 #include "GrPipeline.h"
13 #include "GrProcessor.h"
14 #include "GrProcOptInfo.h"
15 #include "glsl/GrGLSLBlend.h"
16 #include "glsl/GrGLSLFragmentShaderBuilder.h"
17 #include "glsl/GrGLSLUniformHandler.h"
18 #include "glsl/GrGLSLXferProcessor.h"
19 
20 class CoverageSetOpXP : public GrXferProcessor {
21 public:
Create(SkRegion::Op regionOp,bool invertCoverage)22     static GrXferProcessor* Create(SkRegion::Op regionOp, bool invertCoverage) {
23         return new CoverageSetOpXP(regionOp, invertCoverage);
24     }
25 
26     ~CoverageSetOpXP() override;
27 
name() const28     const char* name() const override { return "Coverage Set Op"; }
29 
30     GrGLSLXferProcessor* createGLSLInstance() const override;
31 
invertCoverage() const32     bool invertCoverage() const { return fInvertCoverage; }
33 
34 private:
35     CoverageSetOpXP(SkRegion::Op regionOp, bool fInvertCoverage);
36 
37     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
38                                                  bool doesStencilWrite,
39                                                  GrColor* color,
40                                                  const GrCaps& caps) const override;
41 
42     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
43 
44     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override;
45 
onIsEqual(const GrXferProcessor & xpBase) const46     bool onIsEqual(const GrXferProcessor& xpBase) const override {
47         const CoverageSetOpXP& xp = xpBase.cast<CoverageSetOpXP>();
48         return (fRegionOp == xp.fRegionOp &&
49                 fInvertCoverage == xp.fInvertCoverage);
50     }
51 
52     SkRegion::Op fRegionOp;
53     bool         fInvertCoverage;
54 
55     typedef GrXferProcessor INHERITED;
56 };
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 
60 class GLCoverageSetOpXP : public GrGLSLXferProcessor {
61 public:
GLCoverageSetOpXP(const GrProcessor &)62     GLCoverageSetOpXP(const GrProcessor&) {}
63 
~GLCoverageSetOpXP()64     ~GLCoverageSetOpXP() override {}
65 
GenKey(const GrProcessor & processor,const GrGLSLCaps & caps,GrProcessorKeyBuilder * b)66     static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
67                        GrProcessorKeyBuilder* b) {
68         const CoverageSetOpXP& xp = processor.cast<CoverageSetOpXP>();
69         uint32_t key = xp.invertCoverage() ?  0x0 : 0x1;
70         b->add32(key);
71     }
72 
73 private:
emitOutputsForBlendState(const EmitArgs & args)74     void emitOutputsForBlendState(const EmitArgs& args) override {
75         const CoverageSetOpXP& xp = args.fXP.cast<CoverageSetOpXP>();
76         GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
77 
78         if (xp.invertCoverage()) {
79             fragBuilder->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage);
80         } else {
81             fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
82         }
83     }
84 
onSetData(const GrGLSLProgramDataManager &,const GrXferProcessor &)85     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
86 
87     typedef GrGLSLXferProcessor INHERITED;
88 };
89 
90 ///////////////////////////////////////////////////////////////////////////////
91 
CoverageSetOpXP(SkRegion::Op regionOp,bool invertCoverage)92 CoverageSetOpXP::CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage)
93     : fRegionOp(regionOp)
94     , fInvertCoverage(invertCoverage) {
95     this->initClassID<CoverageSetOpXP>();
96 }
97 
~CoverageSetOpXP()98 CoverageSetOpXP::~CoverageSetOpXP() {
99 }
100 
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const101 void CoverageSetOpXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
102                                             GrProcessorKeyBuilder* b) const {
103     GLCoverageSetOpXP::GenKey(*this, caps, b);
104 }
105 
createGLSLInstance() const106 GrGLSLXferProcessor* CoverageSetOpXP::createGLSLInstance() const {
107     return new GLCoverageSetOpXP(*this);
108 }
109 
110 GrXferProcessor::OptFlags
onGetOptimizations(const GrPipelineOptimizations & optimizations,bool doesStencilWrite,GrColor * color,const GrCaps & caps) const111 CoverageSetOpXP::onGetOptimizations(const GrPipelineOptimizations& optimizations,
112                                     bool doesStencilWrite,
113                                     GrColor* color,
114                                     const GrCaps& caps) const {
115     // We never look at the color input
116     return GrXferProcessor::kIgnoreColor_OptFlag;
117 }
118 
onGetBlendInfo(GrXferProcessor::BlendInfo * blendInfo) const119 void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const {
120     switch (fRegionOp) {
121         case SkRegion::kReplace_Op:
122             blendInfo->fSrcBlend = kOne_GrBlendCoeff;
123             blendInfo->fDstBlend = kZero_GrBlendCoeff;
124             break;
125         case SkRegion::kIntersect_Op:
126             blendInfo->fSrcBlend = kDC_GrBlendCoeff;
127             blendInfo->fDstBlend = kZero_GrBlendCoeff;
128             break;
129         case SkRegion::kUnion_Op:
130             blendInfo->fSrcBlend = kOne_GrBlendCoeff;
131             blendInfo->fDstBlend = kISC_GrBlendCoeff;
132             break;
133         case SkRegion::kXOR_Op:
134             blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
135             blendInfo->fDstBlend = kISC_GrBlendCoeff;
136             break;
137         case SkRegion::kDifference_Op:
138             blendInfo->fSrcBlend = kZero_GrBlendCoeff;
139             blendInfo->fDstBlend = kISC_GrBlendCoeff;
140             break;
141         case SkRegion::kReverseDifference_Op:
142             blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
143             blendInfo->fDstBlend = kZero_GrBlendCoeff;
144             break;
145     }
146     blendInfo->fBlendConstant = 0;
147 }
148 
149 ///////////////////////////////////////////////////////////////////////////////
150 
151 class ShaderCSOXferProcessor : public GrXferProcessor {
152 public:
ShaderCSOXferProcessor(const DstTexture * dstTexture,bool hasMixedSamples,SkRegion::Op regionOp,bool invertCoverage)153     ShaderCSOXferProcessor(const DstTexture* dstTexture,
154                            bool hasMixedSamples,
155                            SkRegion::Op regionOp,
156                            bool invertCoverage)
157         : INHERITED(dstTexture, true, hasMixedSamples)
158         , fRegionOp(regionOp)
159         , fInvertCoverage(invertCoverage) {
160         this->initClassID<ShaderCSOXferProcessor>();
161     }
162 
name() const163     const char* name() const override { return "Coverage Set Op Shader"; }
164 
165     GrGLSLXferProcessor* createGLSLInstance() const override;
166 
regionOp() const167     SkRegion::Op regionOp() const { return fRegionOp; }
invertCoverage() const168     bool invertCoverage() const { return fInvertCoverage; }
169 
170 private:
onGetOptimizations(const GrPipelineOptimizations &,bool,GrColor *,const GrCaps &) const171     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*,
172                                                  const GrCaps&) const override {
173         // We never look at the color input
174         return GrXferProcessor::kIgnoreColor_OptFlag;
175     }
176 
177     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
178 
onIsEqual(const GrXferProcessor & xpBase) const179     bool onIsEqual(const GrXferProcessor& xpBase) const override {
180         const ShaderCSOXferProcessor& xp = xpBase.cast<ShaderCSOXferProcessor>();
181         return (fRegionOp == xp.fRegionOp &&
182                 fInvertCoverage == xp.fInvertCoverage);
183     }
184 
185     SkRegion::Op fRegionOp;
186     bool         fInvertCoverage;
187 
188     typedef GrXferProcessor INHERITED;
189 };
190 
191 ///////////////////////////////////////////////////////////////////////////////
192 
193 class GLShaderCSOXferProcessor : public GrGLSLXferProcessor {
194 public:
GenKey(const GrProcessor & processor,GrProcessorKeyBuilder * b)195     static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
196         const ShaderCSOXferProcessor& xp = processor.cast<ShaderCSOXferProcessor>();
197         b->add32(xp.regionOp());
198         uint32_t key = xp.invertCoverage() ?  0x0 : 0x1;
199         b->add32(key);
200     }
201 
202 private:
emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder * fragBuilder,GrGLSLUniformHandler * uniformHandler,const char * srcColor,const char * srcCoverage,const char * dstColor,const char * outColor,const char * outColorSecondary,const GrXferProcessor & proc)203     void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
204                                  GrGLSLUniformHandler* uniformHandler,
205                                  const char* srcColor,
206                                  const char* srcCoverage,
207                                  const char* dstColor,
208                                  const char* outColor,
209                                  const char* outColorSecondary,
210                                  const GrXferProcessor& proc) override {
211         const ShaderCSOXferProcessor& xp = proc.cast<ShaderCSOXferProcessor>();
212 
213         if (xp.invertCoverage()) {
214             fragBuilder->codeAppendf("%s = 1.0 - %s;", outColor, srcCoverage);
215         } else {
216             fragBuilder->codeAppendf("%s = %s;", outColor, srcCoverage);
217         }
218 
219         GrGLSLBlend::AppendRegionOp(fragBuilder, outColor, dstColor, outColor, xp.regionOp());
220     }
221 
onSetData(const GrGLSLProgramDataManager &,const GrXferProcessor &)222     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
223 
224     typedef GrGLSLXferProcessor INHERITED;
225 };
226 
227 ///////////////////////////////////////////////////////////////////////////////
228 
onGetGLSLProcessorKey(const GrGLSLCaps &,GrProcessorKeyBuilder * b) const229 void ShaderCSOXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&,
230                                                    GrProcessorKeyBuilder* b) const {
231     GLShaderCSOXferProcessor::GenKey(*this, b);
232 }
233 
createGLSLInstance() const234 GrGLSLXferProcessor* ShaderCSOXferProcessor::createGLSLInstance() const {
235     return new GLShaderCSOXferProcessor;
236 }
237 
238 ///////////////////////////////////////////////////////////////////////////////
239 //
GrCoverageSetOpXPFactory(SkRegion::Op regionOp,bool invertCoverage)240 GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage)
241     : fRegionOp(regionOp)
242     , fInvertCoverage(invertCoverage) {
243     this->initClassID<GrCoverageSetOpXPFactory>();
244 }
245 
Make(SkRegion::Op regionOp,bool invertCoverage)246 sk_sp<GrXPFactory> GrCoverageSetOpXPFactory::Make(SkRegion::Op regionOp, bool invertCoverage) {
247     switch (regionOp) {
248         case SkRegion::kReplace_Op: {
249             if (invertCoverage) {
250                 static GrCoverageSetOpXPFactory gReplaceCDXPFI(regionOp, invertCoverage);
251                 return sk_sp<GrXPFactory>(SkRef(&gReplaceCDXPFI));
252             } else {
253                 static GrCoverageSetOpXPFactory gReplaceCDXPF(regionOp, invertCoverage);
254                 return sk_sp<GrXPFactory>(SkRef(&gReplaceCDXPF));
255             }
256             break;
257         }
258         case SkRegion::kIntersect_Op: {
259             if (invertCoverage) {
260                 static GrCoverageSetOpXPFactory gIntersectCDXPFI(regionOp, invertCoverage);
261                 return sk_sp<GrXPFactory>(SkRef(&gIntersectCDXPFI));
262             } else {
263                 static GrCoverageSetOpXPFactory gIntersectCDXPF(regionOp, invertCoverage);
264                 return sk_sp<GrXPFactory>(SkRef(&gIntersectCDXPF));
265             }
266             break;
267         }
268         case SkRegion::kUnion_Op: {
269             if (invertCoverage) {
270                 static GrCoverageSetOpXPFactory gUnionCDXPFI(regionOp, invertCoverage);
271                 return sk_sp<GrXPFactory>(SkRef(&gUnionCDXPFI));
272             } else {
273                 static GrCoverageSetOpXPFactory gUnionCDXPF(regionOp, invertCoverage);
274                 return sk_sp<GrXPFactory>(SkRef(&gUnionCDXPF));
275             }
276             break;
277         }
278         case SkRegion::kXOR_Op: {
279             if (invertCoverage) {
280                 static GrCoverageSetOpXPFactory gXORCDXPFI(regionOp, invertCoverage);
281                 return sk_sp<GrXPFactory>(SkRef(&gXORCDXPFI));
282             } else {
283                 static GrCoverageSetOpXPFactory gXORCDXPF(regionOp, invertCoverage);
284                 return sk_sp<GrXPFactory>(SkRef(&gXORCDXPF));
285             }
286             break;
287         }
288         case SkRegion::kDifference_Op: {
289             if (invertCoverage) {
290                 static GrCoverageSetOpXPFactory gDifferenceCDXPFI(regionOp, invertCoverage);
291                 return sk_sp<GrXPFactory>(SkRef(&gDifferenceCDXPFI));
292             } else {
293                 static GrCoverageSetOpXPFactory gDifferenceCDXPF(regionOp, invertCoverage);
294                 return sk_sp<GrXPFactory>(SkRef(&gDifferenceCDXPF));
295             }
296             break;
297         }
298         case SkRegion::kReverseDifference_Op: {
299             if (invertCoverage) {
300                 static GrCoverageSetOpXPFactory gRevDiffCDXPFI(regionOp, invertCoverage);
301                 return sk_sp<GrXPFactory>(SkRef(&gRevDiffCDXPFI));
302             } else {
303                 static GrCoverageSetOpXPFactory gRevDiffCDXPF(regionOp, invertCoverage);
304                 return sk_sp<GrXPFactory>(SkRef(&gRevDiffCDXPF));
305             }
306             break;
307         }
308         default:
309             return nullptr;
310     }
311 }
312 
313 GrXferProcessor*
onCreateXferProcessor(const GrCaps & caps,const GrPipelineOptimizations & optimizations,bool hasMixedSamples,const DstTexture * dst) const314 GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrCaps& caps,
315                                                 const GrPipelineOptimizations& optimizations,
316                                                 bool hasMixedSamples,
317                                                 const DstTexture* dst) const {
318     // We don't support inverting coverage with mixed samples. We don't expect to ever want this in
319     // the future, however we could at some point make this work using an inverted coverage
320     // modulation table. Note that an inverted table still won't work if there are coverage procs.
321     if (fInvertCoverage && hasMixedSamples) {
322         SkASSERT(false);
323         return nullptr;
324     }
325 
326     if (optimizations.fOverrides.fUsePLSDstRead) {
327         return new ShaderCSOXferProcessor(dst, hasMixedSamples, fRegionOp, fInvertCoverage);
328     }
329     return CoverageSetOpXP::Create(fRegionOp, fInvertCoverage);
330 }
331 
getInvariantBlendedColor(const GrProcOptInfo & colorPOI,InvariantBlendedColor * blendedColor) const332 void GrCoverageSetOpXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
333                                                         InvariantBlendedColor* blendedColor) const {
334     blendedColor->fWillBlendWithDst = SkRegion::kReplace_Op != fRegionOp;
335     blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
336 }
337 
338 GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory);
339 
TestCreate(GrProcessorTestData * d)340 sk_sp<GrXPFactory> GrCoverageSetOpXPFactory::TestCreate(GrProcessorTestData* d) {
341     SkRegion::Op regionOp = SkRegion::Op(d->fRandom->nextULessThan(SkRegion::kLastOp + 1));
342     bool invertCoverage = !d->fDrawContext->hasMixedSamples() && d->fRandom->nextBool();
343     return GrCoverageSetOpXPFactory::Make(regionOp, invertCoverage);
344 }
345