blob: f0ec1f9b00b4d7c74ce4431cb6dd551ab54c811e [file] [log] [blame]
egdaniel87509242014-12-17 13:37:13 -08001
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "effects/GrCoverageSetOpXP.h"
10#include "GrColor.h"
11#include "GrDrawTargetCaps.h"
egdaniel87509242014-12-17 13:37:13 -080012#include "GrProcessor.h"
13#include "GrProcOptInfo.h"
14#include "gl/GrGLXferProcessor.h"
15#include "gl/builders/GrGLFragmentShaderBuilder.h"
16#include "gl/builders/GrGLProgramBuilder.h"
17
egdaniel41d4f092015-02-09 07:51:00 -080018/**
19 * This xfer processor directly blends the the src coverage with the dst using a set operator. It is
20 * useful for rendering coverage masks using CSG. It can optionally invert the src coverage before
21 * applying the set operator.
22 * */
23class CoverageSetOpXP : public GrXferProcessor {
egdaniel87509242014-12-17 13:37:13 -080024public:
egdaniel41d4f092015-02-09 07:51:00 -080025 static GrXferProcessor* Create(SkRegion::Op regionOp, bool invertCoverage) {
26 return SkNEW_ARGS(CoverageSetOpXP, (regionOp, invertCoverage));
27 }
egdaniel87509242014-12-17 13:37:13 -080028
egdaniel41d4f092015-02-09 07:51:00 -080029 ~CoverageSetOpXP() SK_OVERRIDE;
30
31 const char* name() const SK_OVERRIDE { return "Coverage Set Op"; }
32
33 GrGLXferProcessor* createGLInstance() const SK_OVERRIDE;
34
35 bool hasSecondaryOutput() const SK_OVERRIDE { return false; }
36
37 GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
38 const GrProcOptInfo& coveragePOI,
39 bool doesStencilWrite,
40 GrColor* color,
41 const GrDrawTargetCaps& caps) SK_OVERRIDE;
42
43 void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE;
44
45 bool invertCoverage() const { return fInvertCoverage; }
46
47private:
48 CoverageSetOpXP(SkRegion::Op regionOp, bool fInvertCoverage);
49
50 void onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const SK_OVERRIDE;
51
52 bool onIsEqual(const GrXferProcessor& xpBase) const SK_OVERRIDE {
53 const CoverageSetOpXP& xp = xpBase.cast<CoverageSetOpXP>();
54 return (fRegionOp == xp.fRegionOp &&
55 fInvertCoverage == xp.fInvertCoverage);
56 }
57
58 SkRegion::Op fRegionOp;
59 bool fInvertCoverage;
60
61 typedef GrXferProcessor INHERITED;
62};
63
64///////////////////////////////////////////////////////////////////////////////
65
66class GLCoverageSetOpXP : public GrGLXferProcessor {
67public:
68 GLCoverageSetOpXP(const GrProcessor&) {}
69
70 ~GLCoverageSetOpXP() SK_OVERRIDE {}
egdaniel87509242014-12-17 13:37:13 -080071
bsalomon50785a32015-02-06 07:02:37 -080072 static void GenKey(const GrProcessor& processor, const GrGLCaps& caps,
73 GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -080074 const CoverageSetOpXP& xp = processor.cast<CoverageSetOpXP>();
bsalomon50785a32015-02-06 07:02:37 -080075 uint32_t key = xp.invertCoverage() ? 0x0 : 0x1;
76 b->add32(key);
77 };
78
79private:
80 void onEmitCode(const EmitArgs& args) SK_OVERRIDE {
egdaniel41d4f092015-02-09 07:51:00 -080081 const CoverageSetOpXP& xp = args.fXP.cast<CoverageSetOpXP>();
egdaniel87509242014-12-17 13:37:13 -080082 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
83
84 if (xp.invertCoverage()) {
85 fsBuilder->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage);
86 } else {
87 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
88 }
89 }
90
bsalomon50785a32015-02-06 07:02:37 -080091 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {};
egdaniel87509242014-12-17 13:37:13 -080092
egdaniel87509242014-12-17 13:37:13 -080093 typedef GrGLXferProcessor INHERITED;
94};
95
96///////////////////////////////////////////////////////////////////////////////
97
egdaniel41d4f092015-02-09 07:51:00 -080098CoverageSetOpXP::CoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage)
egdaniel87509242014-12-17 13:37:13 -080099 : fRegionOp(regionOp)
100 , fInvertCoverage(invertCoverage) {
egdaniel41d4f092015-02-09 07:51:00 -0800101 this->initClassID<CoverageSetOpXP>();
egdaniel87509242014-12-17 13:37:13 -0800102}
103
egdaniel41d4f092015-02-09 07:51:00 -0800104CoverageSetOpXP::~CoverageSetOpXP() {
egdaniel87509242014-12-17 13:37:13 -0800105}
106
egdaniel41d4f092015-02-09 07:51:00 -0800107void CoverageSetOpXP::onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
108 GLCoverageSetOpXP::GenKey(*this, caps, b);
egdaniel87509242014-12-17 13:37:13 -0800109}
110
egdaniel41d4f092015-02-09 07:51:00 -0800111GrGLXferProcessor* CoverageSetOpXP::createGLInstance() const {
112 return SkNEW_ARGS(GLCoverageSetOpXP, (*this));
egdaniel87509242014-12-17 13:37:13 -0800113}
114
115GrXferProcessor::OptFlags
egdaniel41d4f092015-02-09 07:51:00 -0800116CoverageSetOpXP::getOptimizations(const GrProcOptInfo& colorPOI,
117 const GrProcOptInfo& coveragePOI,
118 bool doesStencilWrite,
119 GrColor* color,
120 const GrDrawTargetCaps& caps) {
egdaniel87509242014-12-17 13:37:13 -0800121 // We never look at the color input
122 return GrXferProcessor::kIgnoreColor_OptFlag;
123}
124
egdaniel41d4f092015-02-09 07:51:00 -0800125void CoverageSetOpXP::getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const {
egdaniel87509242014-12-17 13:37:13 -0800126 switch (fRegionOp) {
127 case SkRegion::kReplace_Op:
128 blendInfo->fSrcBlend = kOne_GrBlendCoeff;
129 blendInfo->fDstBlend = kZero_GrBlendCoeff;
130 break;
131 case SkRegion::kIntersect_Op:
132 blendInfo->fSrcBlend = kDC_GrBlendCoeff;
133 blendInfo->fDstBlend = kZero_GrBlendCoeff;
134 break;
135 case SkRegion::kUnion_Op:
136 blendInfo->fSrcBlend = kOne_GrBlendCoeff;
137 blendInfo->fDstBlend = kISC_GrBlendCoeff;
138 break;
139 case SkRegion::kXOR_Op:
140 blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
141 blendInfo->fDstBlend = kISC_GrBlendCoeff;
142 break;
143 case SkRegion::kDifference_Op:
144 blendInfo->fSrcBlend = kZero_GrBlendCoeff;
145 blendInfo->fDstBlend = kISC_GrBlendCoeff;
146 break;
147 case SkRegion::kReverseDifference_Op:
148 blendInfo->fSrcBlend = kIDC_GrBlendCoeff;
149 blendInfo->fDstBlend = kZero_GrBlendCoeff;
150 break;
151 }
152 blendInfo->fBlendConstant = 0;
153}
154
155///////////////////////////////////////////////////////////////////////////////
156
157GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage)
158 : fRegionOp(regionOp)
159 , fInvertCoverage(invertCoverage) {
160 this->initClassID<GrCoverageSetOpXPFactory>();
161}
162
163GrXPFactory* GrCoverageSetOpXPFactory::Create(SkRegion::Op regionOp, bool invertCoverage) {
164 switch (regionOp) {
165 case SkRegion::kReplace_Op: {
166 if (invertCoverage) {
167 static GrCoverageSetOpXPFactory gReplaceCDXPFI(regionOp, invertCoverage);
168 return SkRef(&gReplaceCDXPFI);
169 } else {
170 static GrCoverageSetOpXPFactory gReplaceCDXPF(regionOp, invertCoverage);
171 return SkRef(&gReplaceCDXPF);
172 }
173 break;
174 }
175 case SkRegion::kIntersect_Op: {
176 if (invertCoverage) {
177 static GrCoverageSetOpXPFactory gIntersectCDXPFI(regionOp, invertCoverage);
178 return SkRef(&gIntersectCDXPFI);
179 } else {
180 static GrCoverageSetOpXPFactory gIntersectCDXPF(regionOp, invertCoverage);
181 return SkRef(&gIntersectCDXPF);
182 }
183 break;
184 }
185 case SkRegion::kUnion_Op: {
186 if (invertCoverage) {
187 static GrCoverageSetOpXPFactory gUnionCDXPFI(regionOp, invertCoverage);
188 return SkRef(&gUnionCDXPFI);
189 } else {
190 static GrCoverageSetOpXPFactory gUnionCDXPF(regionOp, invertCoverage);
191 return SkRef(&gUnionCDXPF);
192 }
193 break;
194 }
195 case SkRegion::kXOR_Op: {
196 if (invertCoverage) {
197 static GrCoverageSetOpXPFactory gXORCDXPFI(regionOp, invertCoverage);
198 return SkRef(&gXORCDXPFI);
199 } else {
200 static GrCoverageSetOpXPFactory gXORCDXPF(regionOp, invertCoverage);
201 return SkRef(&gXORCDXPF);
202 }
203 break;
204 }
205 case SkRegion::kDifference_Op: {
206 if (invertCoverage) {
207 static GrCoverageSetOpXPFactory gDifferenceCDXPFI(regionOp, invertCoverage);
208 return SkRef(&gDifferenceCDXPFI);
209 } else {
210 static GrCoverageSetOpXPFactory gDifferenceCDXPF(regionOp, invertCoverage);
211 return SkRef(&gDifferenceCDXPF);
212 }
213 break;
214 }
215 case SkRegion::kReverseDifference_Op: {
216 if (invertCoverage) {
217 static GrCoverageSetOpXPFactory gRevDiffCDXPFI(regionOp, invertCoverage);
218 return SkRef(&gRevDiffCDXPFI);
219 } else {
220 static GrCoverageSetOpXPFactory gRevDiffCDXPF(regionOp, invertCoverage);
221 return SkRef(&gRevDiffCDXPF);
222 }
223 break;
224 }
225 default:
226 return NULL;
227 }
228}
229
bsalomon50785a32015-02-06 07:02:37 -0800230GrXferProcessor*
231GrCoverageSetOpXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI,
232 const GrProcOptInfo& covPOI,
233 const GrDeviceCoordTexture* dstCopy) const {
egdaniel41d4f092015-02-09 07:51:00 -0800234 return CoverageSetOpXP::Create(fRegionOp, fInvertCoverage);
egdaniel87509242014-12-17 13:37:13 -0800235}
236
egdaniel9e4ecdc2014-12-18 12:44:55 -0800237void GrCoverageSetOpXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
238 const GrProcOptInfo& coveragePOI,
egdaniel9e4ecdc2014-12-18 12:44:55 -0800239 GrXPFactory::InvariantOutput* output) const {
240 if (SkRegion::kReplace_Op == fRegionOp) {
241 if (coveragePOI.isSolidWhite()) {
242 output->fBlendedColor = GrColor_WHITE;
243 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
egdaniel87509242014-12-17 13:37:13 -0800244 } else {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800245 output->fBlendedColorFlags = 0;
egdaniel87509242014-12-17 13:37:13 -0800246 }
egdaniel9e4ecdc2014-12-18 12:44:55 -0800247
egdaniel71e236c2015-01-20 06:34:51 -0800248 output->fWillBlendWithDst = false;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800249 } else {
250 output->fBlendedColorFlags = 0;
251 output->fWillBlendWithDst = true;
egdaniel87509242014-12-17 13:37:13 -0800252 }
egdaniel87509242014-12-17 13:37:13 -0800253}
254
egdaniel87509242014-12-17 13:37:13 -0800255GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory);
256
257GrXPFactory* GrCoverageSetOpXPFactory::TestCreate(SkRandom* random,
258 GrContext*,
259 const GrDrawTargetCaps&,
260 GrTexture*[]) {
261 SkRegion::Op regionOp = SkRegion::Op(random->nextULessThan(SkRegion::kLastOp + 1));
262 bool invertCoverage = random->nextBool();
263 return GrCoverageSetOpXPFactory::Create(regionOp, invertCoverage);
264}
265