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