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