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 "src/gpu/GrCaps.h"
9#include "src/gpu/GrColor.h"
10#include "src/gpu/GrPipeline.h"
11#include "src/gpu/GrProcessor.h"
12#include "src/gpu/GrRenderTargetContext.h"
13#include "src/gpu/effects/GrCoverageSetOpXP.h"
14#include "src/gpu/glsl/GrGLSLBlend.h"
15#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
16#include "src/gpu/glsl/GrGLSLUniformHandler.h"
17#include "src/gpu/glsl/GrGLSLXferProcessor.h"
18
19class CoverageSetOpXP : public GrXferProcessor {
20public:
21 CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage)
22 : INHERITED(kCoverageSetOpXP_ClassID)
23 , fRegionOp(regionOp)
24 , fInvertCoverage(invertCoverage) {}
25
26 const char* name() const override { return "Coverage Set Op"; }
27
28 GrGLSLXferProcessor* createGLSLInstance() const override;
29
30 bool invertCoverage() const { return fInvertCoverage; }
31
32private:
33
34 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
35
36 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override;
37
38 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
52class GLCoverageSetOpXP : public GrGLSLXferProcessor {
53public:
54 GLCoverageSetOpXP(const GrProcessor&) {}
55
56 ~GLCoverageSetOpXP() override {}
57
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
65private:
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
77 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
78
79 typedef GrGLSLXferProcessor INHERITED;
80};
81
82///////////////////////////////////////////////////////////////////////////////
83
84void CoverageSetOpXP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
85 GrProcessorKeyBuilder* b) const {
86 GLCoverageSetOpXP::GenKey(*this, caps, b);
87}
88
89GrGLSLXferProcessor* CoverageSetOpXP::createGLSLInstance() const {
90 return new GLCoverageSetOpXP(*this);
91}
92
93void 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 = SK_PMColor4fTRANSPARENT;
121}
122
123///////////////////////////////////////////////////////////////////////////////
124
125constexpr GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp,
126 bool invertCoverage)
127 : fRegionOp(regionOp), fInvertCoverage(invertCoverage) {}
128
129const GrXPFactory* GrCoverageSetOpXPFactory::Get(SkRegion::Op regionOp, bool invertCoverage) {
130 switch (regionOp) {
131 case SkRegion::kReplace_Op: {
132 if (invertCoverage) {
133 static constexpr const GrCoverageSetOpXPFactory gReplaceCDXPFI(
134 SkRegion::kReplace_Op, true);
135 return &gReplaceCDXPFI;
136 } else {
137 static constexpr const GrCoverageSetOpXPFactory gReplaceCDXPF(SkRegion::kReplace_Op,
138 false);
139 return &gReplaceCDXPF;
140 }
141 }
142 case SkRegion::kIntersect_Op: {
143 if (invertCoverage) {
144 static constexpr const GrCoverageSetOpXPFactory gIntersectCDXPFI(
145 SkRegion::kIntersect_Op, true);
146 return &gIntersectCDXPFI;
147 } else {
148 static constexpr const GrCoverageSetOpXPFactory gIntersectCDXPF(
149 SkRegion::kIntersect_Op, false);
150 return &gIntersectCDXPF;
151 }
152 }
153 case SkRegion::kUnion_Op: {
154 if (invertCoverage) {
155 static constexpr const GrCoverageSetOpXPFactory gUnionCDXPFI(SkRegion::kUnion_Op,
156 true);
157 return &gUnionCDXPFI;
158 } else {
159 static constexpr const GrCoverageSetOpXPFactory gUnionCDXPF(SkRegion::kUnion_Op,
160 false);
161 return &gUnionCDXPF;
162 }
163 }
164 case SkRegion::kXOR_Op: {
165 if (invertCoverage) {
166 static constexpr const GrCoverageSetOpXPFactory gXORCDXPFI(SkRegion::kXOR_Op, true);
167 return &gXORCDXPFI;
168 } else {
169 static constexpr const GrCoverageSetOpXPFactory gXORCDXPF(SkRegion::kXOR_Op, false);
170 return &gXORCDXPF;
171 }
172 }
173 case SkRegion::kDifference_Op: {
174 if (invertCoverage) {
175 static constexpr const GrCoverageSetOpXPFactory gDifferenceCDXPFI(
176 SkRegion::kDifference_Op, true);
177 return &gDifferenceCDXPFI;
178 } else {
179 static constexpr const GrCoverageSetOpXPFactory gDifferenceCDXPF(
180 SkRegion::kDifference_Op, false);
181 return &gDifferenceCDXPF;
182 }
183 }
184 case SkRegion::kReverseDifference_Op: {
185 if (invertCoverage) {
186 static constexpr const GrCoverageSetOpXPFactory gRevDiffCDXPFI(
187 SkRegion::kReverseDifference_Op, true);
188 return &gRevDiffCDXPFI;
189 } else {
190 static constexpr const GrCoverageSetOpXPFactory gRevDiffCDXPF(
191 SkRegion::kReverseDifference_Op, false);
192 return &gRevDiffCDXPF;
193 }
194 }
195 }
196 SK_ABORT("Unknown region op.");
197}
198
199sk_sp<const GrXferProcessor> GrCoverageSetOpXPFactory::makeXferProcessor(
200 const GrProcessorAnalysisColor&,
201 GrProcessorAnalysisCoverage,
202 bool hasMixedSamples,
203 const GrCaps& caps,
204 GrClampType) const {
205 // We don't support inverting coverage with mixed samples. We don't expect to ever want this in
206 // the future, however we could at some point make this work using an inverted coverage
207 // modulation table. Note that an inverted table still won't work if there are coverage procs.
208 if (fInvertCoverage && hasMixedSamples) {
209 SkASSERT(false);
210 return nullptr;
211 }
212
213 return sk_sp<GrXferProcessor>(new CoverageSetOpXP(fRegionOp, fInvertCoverage));
214}
215
216GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory);
217
218#if GR_TEST_UTILS
219const GrXPFactory* GrCoverageSetOpXPFactory::TestGet(GrProcessorTestData* d) {
220 SkRegion::Op regionOp = SkRegion::Op(d->fRandom->nextULessThan(SkRegion::kLastOp + 1));
221 bool invertCoverage = d->fRandom->nextBool();
222 return GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage);
223}
224#endif
225