• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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/GrShaderCaps.h"
9 #include "src/gpu/effects/GrBezierEffect.h"
10 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
11 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
12 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
13 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
14 #include "src/gpu/glsl/GrGLSLUtil.h"
15 #include "src/gpu/glsl/GrGLSLVarying.h"
16 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
17 
18 class GrGLConicEffect : public GrGLSLGeometryProcessor {
19 public:
20     GrGLConicEffect(const GrGeometryProcessor&);
21 
22     void onEmitCode(EmitArgs&, GrGPArgs*) override;
23 
24     static inline void GenKey(const GrGeometryProcessor&,
25                               const GrShaderCaps&,
26                               GrProcessorKeyBuilder*);
27 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & primProc,const CoordTransformRange & transformRange)28     void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
29                  const CoordTransformRange& transformRange) override {
30         const GrConicEffect& ce = primProc.cast<GrConicEffect>();
31 
32         if (!ce.viewMatrix().isIdentity() &&
33             !SkMatrixPriv::CheapEqual(fViewMatrix, ce.viewMatrix()))
34         {
35             fViewMatrix = ce.viewMatrix();
36             float viewMatrix[3 * 3];
37             GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
38             pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
39         }
40 
41         if (ce.color() != fColor) {
42             pdman.set4fv(fColorUniform, 1, ce.color().vec());
43             fColor = ce.color();
44         }
45 
46         if (ce.coverageScale() != 0xff && ce.coverageScale() != fCoverageScale) {
47             pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(ce.coverageScale()));
48             fCoverageScale = ce.coverageScale();
49         }
50         this->setTransformDataHelper(ce.localMatrix(), pdman, transformRange);
51     }
52 
53 private:
54     SkMatrix fViewMatrix;
55     SkPMColor4f fColor;
56     uint8_t fCoverageScale;
57     GrClipEdgeType fEdgeType;
58     UniformHandle fColorUniform;
59     UniformHandle fCoverageScaleUniform;
60     UniformHandle fViewMatrixUniform;
61 
62     typedef GrGLSLGeometryProcessor INHERITED;
63 };
64 
GrGLConicEffect(const GrGeometryProcessor & processor)65 GrGLConicEffect::GrGLConicEffect(const GrGeometryProcessor& processor)
66     : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(SK_PMColor4fILLEGAL), fCoverageScale(0xff) {
67     const GrConicEffect& ce = processor.cast<GrConicEffect>();
68     fEdgeType = ce.getEdgeType();
69 }
70 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)71 void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
72     GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
73     const GrConicEffect& gp = args.fGP.cast<GrConicEffect>();
74     GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
75     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
76 
77     // emit attributes
78     varyingHandler->emitAttributes(gp);
79 
80     GrGLSLVarying v(kFloat4_GrSLType);
81     varyingHandler->addVarying("ConicCoeffs", &v);
82     vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inConicCoeffs().name());
83 
84     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
85     // Setup pass through color
86     this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform);
87 
88     // Setup position
89     this->writeOutputPosition(vertBuilder,
90                               uniformHandler,
91                               gpArgs,
92                               gp.inPosition().name(),
93                               gp.viewMatrix(),
94                               &fViewMatrixUniform);
95 
96     // emit transforms with position
97     this->emitTransforms(vertBuilder,
98                          varyingHandler,
99                          uniformHandler,
100                          gp.inPosition().asShaderVar(),
101                          gp.localMatrix(),
102                          args.fFPCoordTransformHandler);
103 
104     // TODO: we should check on the number of bits float and half provide and use the smallest one
105     // that suffices. Additionally we should assert that the upstream code only lets us get here if
106     // either float or half provides the required number of bits.
107 
108     GrShaderVar edgeAlpha("edgeAlpha", kHalf_GrSLType, 0);
109     GrShaderVar dklmdx("dklmdx", kFloat3_GrSLType, 0);
110     GrShaderVar dklmdy("dklmdy", kFloat3_GrSLType, 0);
111     GrShaderVar dfdx("dfdx", kFloat_GrSLType, 0);
112     GrShaderVar dfdy("dfdy", kFloat_GrSLType, 0);
113     GrShaderVar gF("gF", kFloat2_GrSLType, 0);
114     GrShaderVar gFM("gFM", kFloat_GrSLType, 0);
115     GrShaderVar func("func", kFloat_GrSLType, 0);
116 
117     fragBuilder->declAppend(edgeAlpha);
118     fragBuilder->declAppend(dklmdx);
119     fragBuilder->declAppend(dklmdy);
120     fragBuilder->declAppend(dfdx);
121     fragBuilder->declAppend(dfdy);
122     fragBuilder->declAppend(gF);
123     fragBuilder->declAppend(gFM);
124     fragBuilder->declAppend(func);
125 
126     switch (fEdgeType) {
127         case GrClipEdgeType::kHairlineAA: {
128             fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn());
129             fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn());
130             fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
131                                      dfdx.c_str(),
132                                      v.fsIn(), dklmdx.c_str(),
133                                      v.fsIn(), dklmdx.c_str(),
134                                      v.fsIn(), dklmdx.c_str());
135             fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
136                                      dfdy.c_str(),
137                                      v.fsIn(), dklmdy.c_str(),
138                                      v.fsIn(), dklmdy.c_str(),
139                                      v.fsIn(), dklmdy.c_str());
140             fragBuilder->codeAppendf("%s = float2(%s, %s);", gF.c_str(), dfdx.c_str(),
141                                      dfdy.c_str());
142             fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));",
143                                      gFM.c_str(), gF.c_str(), gF.c_str());
144             fragBuilder->codeAppendf("%s = %s.x*%s.x - %s.y*%s.z;",
145                                      func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
146             fragBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str());
147             fragBuilder->codeAppendf("%s = half(%s / %s);",
148                                      edgeAlpha.c_str(), func.c_str(), gFM.c_str());
149             fragBuilder->codeAppendf("%s = max(1.0 - %s, 0.0);",
150                                      edgeAlpha.c_str(), edgeAlpha.c_str());
151             // Add line below for smooth cubic ramp
152             // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
153             break;
154         }
155         case GrClipEdgeType::kFillAA: {
156             fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn());
157             fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn());
158             fragBuilder->codeAppendf("%s ="
159                                      "2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
160                                      dfdx.c_str(),
161                                      v.fsIn(), dklmdx.c_str(),
162                                      v.fsIn(), dklmdx.c_str(),
163                                      v.fsIn(), dklmdx.c_str());
164             fragBuilder->codeAppendf("%s ="
165                                      "2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
166                                      dfdy.c_str(),
167                                      v.fsIn(), dklmdy.c_str(),
168                                      v.fsIn(), dklmdy.c_str(),
169                                      v.fsIn(), dklmdy.c_str());
170             fragBuilder->codeAppendf("%s = float2(%s, %s);", gF.c_str(), dfdx.c_str(),
171                                      dfdy.c_str());
172             fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));",
173                                      gFM.c_str(), gF.c_str(), gF.c_str());
174             fragBuilder->codeAppendf("%s = %s.x * %s.x - %s.y * %s.z;",
175                                      func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
176             fragBuilder->codeAppendf("%s = half(%s / %s);",
177                                      edgeAlpha.c_str(), func.c_str(), gFM.c_str());
178             fragBuilder->codeAppendf("%s = saturate(0.5 - %s);",
179                                      edgeAlpha.c_str(), edgeAlpha.c_str());
180             // Add line below for smooth cubic ramp
181             // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
182             break;
183         }
184         case GrClipEdgeType::kFillBW: {
185             fragBuilder->codeAppendf("%s = half(%s.x * %s.x - %s.y * %s.z);",
186                                      edgeAlpha.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
187             fragBuilder->codeAppendf("%s = half(%s < 0.0);",
188                                      edgeAlpha.c_str(), edgeAlpha.c_str());
189             break;
190         }
191         default:
192             SK_ABORT("Shouldn't get here");
193     }
194 
195     // TODO should we really be doing this?
196     if (gp.coverageScale() != 0xff) {
197         const char* coverageScale;
198         fCoverageScaleUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
199                                                            kFloat_GrSLType,
200                                                            "Coverage",
201                                                            &coverageScale);
202         fragBuilder->codeAppendf("%s = half4(half(%s) * %s);",
203                                  args.fOutputCoverage, coverageScale, edgeAlpha.c_str());
204     } else {
205         fragBuilder->codeAppendf("%s = half4(%s);", args.fOutputCoverage, edgeAlpha.c_str());
206     }
207 }
208 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)209 void GrGLConicEffect::GenKey(const GrGeometryProcessor& gp,
210                              const GrShaderCaps&,
211                              GrProcessorKeyBuilder* b) {
212     const GrConicEffect& ce = gp.cast<GrConicEffect>();
213     uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
214     key |= 0xff != ce.coverageScale() ? 0x8 : 0x0;
215     key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x10 : 0x0;
216     key |= ComputePosKey(ce.viewMatrix()) << 5;
217     b->add32(key);
218 }
219 
220 //////////////////////////////////////////////////////////////////////////////
221 
222 constexpr GrPrimitiveProcessor::Attribute GrConicEffect::kAttributes[];
223 
~GrConicEffect()224 GrConicEffect::~GrConicEffect() {}
225 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const226 void GrConicEffect::getGLSLProcessorKey(const GrShaderCaps& caps,
227                                         GrProcessorKeyBuilder* b) const {
228     GrGLConicEffect::GenKey(*this, caps, b);
229 }
230 
createGLSLInstance(const GrShaderCaps &) const231 GrGLSLPrimitiveProcessor* GrConicEffect::createGLSLInstance(const GrShaderCaps&) const {
232     return new GrGLConicEffect(*this);
233 }
234 
GrConicEffect(const SkPMColor4f & color,const SkMatrix & viewMatrix,uint8_t coverage,GrClipEdgeType edgeType,const SkMatrix & localMatrix,bool usesLocalCoords)235 GrConicEffect::GrConicEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix, uint8_t coverage,
236                              GrClipEdgeType edgeType, const SkMatrix& localMatrix,
237                              bool usesLocalCoords)
238         : INHERITED(kGrConicEffect_ClassID)
239         , fColor(color)
240         , fViewMatrix(viewMatrix)
241         , fLocalMatrix(viewMatrix)
242         , fUsesLocalCoords(usesLocalCoords)
243         , fCoverageScale(coverage)
244         , fEdgeType(edgeType) {
245     this->setVertexAttributes(kAttributes, SK_ARRAY_COUNT(kAttributes));
246 }
247 
248 //////////////////////////////////////////////////////////////////////////////
249 
250 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrConicEffect);
251 
252 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)253 GrGeometryProcessor* GrConicEffect::TestCreate(GrProcessorTestData* d) {
254     GrGeometryProcessor* gp;
255     do {
256         GrClipEdgeType edgeType =
257                 static_cast<GrClipEdgeType>(
258                         d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
259         gp = GrConicEffect::Make(d->allocator(),
260                                  SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)),
261                                  GrTest::TestMatrix(d->fRandom), edgeType, *d->caps(),
262                                  GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool());
263     } while (nullptr == gp);
264     return gp;
265 }
266 #endif
267 
268 //////////////////////////////////////////////////////////////////////////////
269 // Quad
270 //////////////////////////////////////////////////////////////////////////////
271 
272 class GrGLQuadEffect : public GrGLSLGeometryProcessor {
273 public:
274     GrGLQuadEffect(const GrGeometryProcessor&);
275 
276     void onEmitCode(EmitArgs&, GrGPArgs*) override;
277 
278     static inline void GenKey(const GrGeometryProcessor&,
279                               const GrShaderCaps&,
280                               GrProcessorKeyBuilder*);
281 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & primProc,const CoordTransformRange & transformRange)282     void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
283                  const CoordTransformRange& transformRange) override {
284         const GrQuadEffect& qe = primProc.cast<GrQuadEffect>();
285 
286         if (!qe.viewMatrix().isIdentity() &&
287             !SkMatrixPriv::CheapEqual(fViewMatrix, qe.viewMatrix()))
288         {
289             fViewMatrix = qe.viewMatrix();
290             float viewMatrix[3 * 3];
291             GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
292             pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
293         }
294 
295         if (qe.color() != fColor) {
296             pdman.set4fv(fColorUniform, 1, qe.color().vec());
297             fColor = qe.color();
298         }
299 
300         if (qe.coverageScale() != 0xff && qe.coverageScale() != fCoverageScale) {
301             pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(qe.coverageScale()));
302             fCoverageScale = qe.coverageScale();
303         }
304         this->setTransformDataHelper(qe.localMatrix(), pdman, transformRange);
305     }
306 
307 private:
308     SkMatrix fViewMatrix;
309     SkPMColor4f fColor;
310     uint8_t fCoverageScale;
311     GrClipEdgeType fEdgeType;
312     UniformHandle fColorUniform;
313     UniformHandle fCoverageScaleUniform;
314     UniformHandle fViewMatrixUniform;
315 
316     typedef GrGLSLGeometryProcessor INHERITED;
317 };
318 
GrGLQuadEffect(const GrGeometryProcessor & processor)319 GrGLQuadEffect::GrGLQuadEffect(const GrGeometryProcessor& processor)
320     : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(SK_PMColor4fILLEGAL), fCoverageScale(0xff) {
321     const GrQuadEffect& ce = processor.cast<GrQuadEffect>();
322     fEdgeType = ce.getEdgeType();
323 }
324 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)325 void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
326     GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
327     const GrQuadEffect& gp = args.fGP.cast<GrQuadEffect>();
328     GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
329     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
330 
331     // emit attributes
332     varyingHandler->emitAttributes(gp);
333 
334     GrGLSLVarying v(kHalf4_GrSLType);
335     varyingHandler->addVarying("HairQuadEdge", &v);
336     vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inHairQuadEdge().name());
337 
338     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
339     // Setup pass through color
340     this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform);
341 
342     // Setup position
343     this->writeOutputPosition(vertBuilder,
344                               uniformHandler,
345                               gpArgs,
346                               gp.inPosition().name(),
347                               gp.viewMatrix(),
348                               &fViewMatrixUniform);
349 
350     // emit transforms with position
351     this->emitTransforms(vertBuilder,
352                          varyingHandler,
353                          uniformHandler,
354                          gp.inPosition().asShaderVar(),
355                          gp.localMatrix(),
356                          args.fFPCoordTransformHandler);
357 
358     fragBuilder->codeAppendf("half edgeAlpha;");
359 
360     switch (fEdgeType) {
361         case GrClipEdgeType::kHairlineAA: {
362             fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn());
363             fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn());
364             fragBuilder->codeAppendf("half2 gF = half2(2.0 * %s.x * duvdx.x - duvdx.y,"
365                                      "               2.0 * %s.x * duvdy.x - duvdy.y);",
366                                      v.fsIn(), v.fsIn());
367             fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);",
368                                      v.fsIn(), v.fsIn(), v.fsIn());
369             fragBuilder->codeAppend("edgeAlpha = sqrt(edgeAlpha * edgeAlpha / dot(gF, gF));");
370             fragBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);");
371             // Add line below for smooth cubic ramp
372             // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
373             break;
374         }
375         case GrClipEdgeType::kFillAA: {
376             fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn());
377             fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn());
378             fragBuilder->codeAppendf("half2 gF = half2(2.0 * %s.x * duvdx.x - duvdx.y,"
379                                      "               2.0 * %s.x * duvdy.x - duvdy.y);",
380                                      v.fsIn(), v.fsIn());
381             fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);",
382                                      v.fsIn(), v.fsIn(), v.fsIn());
383             fragBuilder->codeAppend("edgeAlpha = edgeAlpha / sqrt(dot(gF, gF));");
384             fragBuilder->codeAppend("edgeAlpha = saturate(0.5 - edgeAlpha);");
385             // Add line below for smooth cubic ramp
386             // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
387             break;
388         }
389         case GrClipEdgeType::kFillBW: {
390             fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);",
391                                      v.fsIn(), v.fsIn(), v.fsIn());
392             fragBuilder->codeAppend("edgeAlpha = half(edgeAlpha < 0.0);");
393             break;
394         }
395         default:
396             SK_ABORT("Shouldn't get here");
397     }
398 
399     if (0xff != gp.coverageScale()) {
400         const char* coverageScale;
401         fCoverageScaleUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
402                                                            kHalf_GrSLType,
403                                                            "Coverage",
404                                                            &coverageScale);
405         fragBuilder->codeAppendf("%s = half4(%s * edgeAlpha);", args.fOutputCoverage,
406                                  coverageScale);
407     } else {
408         fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage);
409     }
410 }
411 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)412 void GrGLQuadEffect::GenKey(const GrGeometryProcessor& gp,
413                             const GrShaderCaps&,
414                             GrProcessorKeyBuilder* b) {
415     const GrQuadEffect& ce = gp.cast<GrQuadEffect>();
416     uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
417     key |= ce.coverageScale() != 0xff ? 0x8 : 0x0;
418     key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x10 : 0x0;
419     key |= ComputePosKey(ce.viewMatrix()) << 5;
420     b->add32(key);
421 }
422 
423 //////////////////////////////////////////////////////////////////////////////
424 
425 constexpr GrPrimitiveProcessor::Attribute GrQuadEffect::kAttributes[];
426 
~GrQuadEffect()427 GrQuadEffect::~GrQuadEffect() {}
428 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const429 void GrQuadEffect::getGLSLProcessorKey(const GrShaderCaps& caps,
430                                        GrProcessorKeyBuilder* b) const {
431     GrGLQuadEffect::GenKey(*this, caps, b);
432 }
433 
createGLSLInstance(const GrShaderCaps &) const434 GrGLSLPrimitiveProcessor* GrQuadEffect::createGLSLInstance(const GrShaderCaps&) const {
435     return new GrGLQuadEffect(*this);
436 }
437 
GrQuadEffect(const SkPMColor4f & color,const SkMatrix & viewMatrix,uint8_t coverage,GrClipEdgeType edgeType,const SkMatrix & localMatrix,bool usesLocalCoords)438 GrQuadEffect::GrQuadEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix, uint8_t coverage,
439                            GrClipEdgeType edgeType, const SkMatrix& localMatrix,
440                            bool usesLocalCoords)
441     : INHERITED(kGrQuadEffect_ClassID)
442     , fColor(color)
443     , fViewMatrix(viewMatrix)
444     , fLocalMatrix(localMatrix)
445     , fUsesLocalCoords(usesLocalCoords)
446     , fCoverageScale(coverage)
447     , fEdgeType(edgeType) {
448     this->setVertexAttributes(kAttributes, SK_ARRAY_COUNT(kAttributes));
449 }
450 
451 //////////////////////////////////////////////////////////////////////////////
452 
453 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrQuadEffect);
454 
455 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)456 GrGeometryProcessor* GrQuadEffect::TestCreate(GrProcessorTestData* d) {
457     GrGeometryProcessor* gp;
458     do {
459         GrClipEdgeType edgeType = static_cast<GrClipEdgeType>(
460                 d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
461         gp = GrQuadEffect::Make(d->allocator(),
462                                 SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)),
463                                 GrTest::TestMatrix(d->fRandom), edgeType, *d->caps(),
464                                 GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool());
465     } while (nullptr == gp);
466     return gp;
467 }
468 #endif
469