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 : fRegionOp(regionOp), fInvertCoverage(invertCoverage) {
23 this->initClassID<CoverageSetOpXP>();
24 }
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 SkFAIL("Unknown region op.");
207 return nullptr;
208 }
209
makeXferProcessor(const GrProcessorAnalysisColor &,GrProcessorAnalysisCoverage,bool hasMixedSamples,const GrCaps & caps) const210 sk_sp<const GrXferProcessor> GrCoverageSetOpXPFactory::makeXferProcessor(
211 const GrProcessorAnalysisColor&,
212 GrProcessorAnalysisCoverage,
213 bool hasMixedSamples,
214 const GrCaps& caps) const {
215 // We don't support inverting coverage with mixed samples. We don't expect to ever want this in
216 // the future, however we could at some point make this work using an inverted coverage
217 // modulation table. Note that an inverted table still won't work if there are coverage procs.
218 if (fInvertCoverage && hasMixedSamples) {
219 SkASSERT(false);
220 return nullptr;
221 }
222
223 return sk_sp<GrXferProcessor>(new CoverageSetOpXP(fRegionOp, fInvertCoverage));
224 }
225
226 GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory);
227
228 #if GR_TEST_UTILS
TestGet(GrProcessorTestData * d)229 const GrXPFactory* GrCoverageSetOpXPFactory::TestGet(GrProcessorTestData* d) {
230 SkRegion::Op regionOp = SkRegion::Op(d->fRandom->nextULessThan(SkRegion::kLastOp + 1));
231 bool isMixedSamples = GrFSAAType::kMixedSamples == d->fRenderTargetContext->fsaaType();
232 bool invertCoverage = !isMixedSamples && d->fRandom->nextBool();
233 return GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage);
234 }
235 #endif
236