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