2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "GrBezierEffect.h"
10 #include "gl/builders/GrGLFullProgramBuilder.h"
11 #include "gl/GrGLProcessor.h"
12 #include "gl/GrGLSL.h"
13 #include "gl/GrGLGeometryProcessor.h"
14 #include "GrTBackendProcessorFactory.h"
16 class GrGLConicEffect : public GrGLGeometryProcessor {
18 GrGLConicEffect(const GrBackendProcessorFactory&, const GrProcessor&);
20 virtual void emitCode(GrGLFullProgramBuilder* builder,
21 const GrGeometryProcessor& geometryProcessor,
22 const GrProcessorKey& key,
23 const char* outputColor,
24 const char* inputColor,
25 const TransformedCoordsArray&,
26 const TextureSamplerArray&) SK_OVERRIDE;
28 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
30 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
33 GrPrimitiveEdgeType fEdgeType;
35 typedef GrGLGeometryProcessor INHERITED;
38 GrGLConicEffect::GrGLConicEffect(const GrBackendProcessorFactory& factory,
39 const GrProcessor& effect)
40 : INHERITED (factory) {
41 const GrConicEffect& ce = effect.cast<GrConicEffect>();
42 fEdgeType = ce.getEdgeType();
45 void GrGLConicEffect::emitCode(GrGLFullProgramBuilder* builder,
46 const GrGeometryProcessor& geometryProcessor,
47 const GrProcessorKey& key,
48 const char* outputColor,
49 const char* inputColor,
50 const TransformedCoordsArray&,
51 const TextureSamplerArray& samplers) {
52 const char *vsName, *fsName;
54 builder->addVarying(kVec4f_GrSLType, "ConicCoeffs",
57 const GrShaderVar& inConicCoeffs = geometryProcessor.cast<GrConicEffect>().inConicCoeffs();
58 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
59 vsBuilder->codeAppendf("%s = %s;", vsName, inConicCoeffs.c_str());
61 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
62 fsBuilder->codeAppend("float edgeAlpha;");
65 case kHairlineAA_GrProcessorEdgeType: {
66 SkAssertResult(fsBuilder->enableFeature(
67 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
68 fsBuilder->codeAppendf("vec3 dklmdx = dFdx(%s.xyz);", fsName);
69 fsBuilder->codeAppendf("vec3 dklmdy = dFdy(%s.xyz);", fsName);
70 fsBuilder->codeAppendf("float dfdx ="
71 "2.0 * %s.x * dklmdx.x - %s.y * dklmdx.z - %s.z * dklmdx.y;",
72 fsName, fsName, fsName);
73 fsBuilder->codeAppendf("float dfdy ="
74 "2.0 * %s.x * dklmdy.x - %s.y * dklmdy.z - %s.z * dklmdy.y;",
75 fsName, fsName, fsName);
76 fsBuilder->codeAppend("vec2 gF = vec2(dfdx, dfdy);");
77 fsBuilder->codeAppend("float gFM = sqrt(dot(gF, gF));");
78 fsBuilder->codeAppendf("float func = %s.x*%s.x - %s.y*%s.z;", fsName, fsName,
80 fsBuilder->codeAppend("func = abs(func);");
81 fsBuilder->codeAppend("edgeAlpha = func / gFM;");
82 fsBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);");
83 // Add line below for smooth cubic ramp
84 // fsBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
87 case kFillAA_GrProcessorEdgeType: {
88 SkAssertResult(fsBuilder->enableFeature(
89 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
90 fsBuilder->codeAppendf("vec3 dklmdx = dFdx(%s.xyz);", fsName);
91 fsBuilder->codeAppendf("vec3 dklmdy = dFdy(%s.xyz);", fsName);
92 fsBuilder->codeAppendf("float dfdx ="
93 "2.0 * %s.x * dklmdx.x - %s.y * dklmdx.z - %s.z * dklmdx.y;",
94 fsName, fsName, fsName);
95 fsBuilder->codeAppendf("float dfdy ="
96 "2.0 * %s.x * dklmdy.x - %s.y * dklmdy.z - %s.z * dklmdy.y;",
97 fsName, fsName, fsName);
98 fsBuilder->codeAppend("vec2 gF = vec2(dfdx, dfdy);");
99 fsBuilder->codeAppend("float gFM = sqrt(dot(gF, gF));");
100 fsBuilder->codeAppendf("float func = %s.x * %s.x - %s.y * %s.z;", fsName, fsName,
102 fsBuilder->codeAppend("edgeAlpha = func / gFM;");
103 fsBuilder->codeAppend("edgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);");
104 // Add line below for smooth cubic ramp
105 // fsBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
108 case kFillBW_GrProcessorEdgeType: {
109 fsBuilder->codeAppendf("edgeAlpha = %s.x * %s.x - %s.y * %s.z;", fsName, fsName,
111 fsBuilder->codeAppend("edgeAlpha = float(edgeAlpha < 0.0);");
115 SkFAIL("Shouldn't get here");
118 fsBuilder->codeAppendf("%s = %s;", outputColor,
119 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
122 void GrGLConicEffect::GenKey(const GrProcessor& processor, const GrGLCaps&,
123 GrProcessorKeyBuilder* b) {
124 const GrConicEffect& ce = processor.cast<GrConicEffect>();
125 uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
129 //////////////////////////////////////////////////////////////////////////////
131 GrConicEffect::~GrConicEffect() {}
133 const GrBackendGeometryProcessorFactory& GrConicEffect::getFactory() const {
134 return GrTBackendGeometryProcessorFactory<GrConicEffect>::getInstance();
137 GrConicEffect::GrConicEffect(GrPrimitiveEdgeType edgeType)
138 : fEdgeType(edgeType)
139 , fInConicCoeffs(this->addVertexAttrib(GrShaderVar("inConicCoeffs",
141 GrShaderVar::kAttribute_TypeModifier))) {
144 bool GrConicEffect::onIsEqual(const GrProcessor& other) const {
145 const GrConicEffect& ce = other.cast<GrConicEffect>();
146 return (ce.fEdgeType == fEdgeType);
149 //////////////////////////////////////////////////////////////////////////////
151 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrConicEffect);
153 GrGeometryProcessor* GrConicEffect::TestCreate(SkRandom* random,
155 const GrDrawTargetCaps& caps,
157 GrGeometryProcessor* gp;
159 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
160 random->nextULessThan(kGrProcessorEdgeTypeCnt));
161 gp = GrConicEffect::Create(edgeType, caps);
162 } while (NULL == gp);
166 //////////////////////////////////////////////////////////////////////////////
168 //////////////////////////////////////////////////////////////////////////////
170 class GrGLQuadEffect : public GrGLGeometryProcessor {
172 GrGLQuadEffect(const GrBackendProcessorFactory&, const GrProcessor&);
174 virtual void emitCode(GrGLFullProgramBuilder* builder,
175 const GrGeometryProcessor& geometryProcessor,
176 const GrProcessorKey& key,
177 const char* outputColor,
178 const char* inputColor,
179 const TransformedCoordsArray&,
180 const TextureSamplerArray&) SK_OVERRIDE;
182 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
184 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
187 GrPrimitiveEdgeType fEdgeType;
189 typedef GrGLGeometryProcessor INHERITED;
192 GrGLQuadEffect::GrGLQuadEffect(const GrBackendProcessorFactory& factory,
193 const GrProcessor& effect)
194 : INHERITED (factory) {
195 const GrQuadEffect& ce = effect.cast<GrQuadEffect>();
196 fEdgeType = ce.getEdgeType();
199 void GrGLQuadEffect::emitCode(GrGLFullProgramBuilder* builder,
200 const GrGeometryProcessor& geometryProcessor,
201 const GrProcessorKey& key,
202 const char* outputColor,
203 const char* inputColor,
204 const TransformedCoordsArray&,
205 const TextureSamplerArray& samplers) {
206 const char *vsName, *fsName;
207 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
209 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
210 const GrShaderVar& inHairQuadEdge = geometryProcessor.cast<GrQuadEffect>().inHairQuadEdge();
211 vsBuilder->codeAppendf("%s = %s;", vsName, inHairQuadEdge.c_str());
213 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
214 fsBuilder->codeAppendf("float edgeAlpha;");
217 case kHairlineAA_GrProcessorEdgeType: {
218 SkAssertResult(fsBuilder->enableFeature(
219 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
220 fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", fsName);
221 fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", fsName);
222 fsBuilder->codeAppendf("vec2 gF = vec2(2.0 * %s.x * duvdx.x - duvdx.y,"
223 " 2.0 * %s.x * duvdy.x - duvdy.y);",
225 fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", fsName, fsName, fsName);
226 fsBuilder->codeAppend("edgeAlpha = sqrt(edgeAlpha * edgeAlpha / dot(gF, gF));");
227 fsBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);");
228 // Add line below for smooth cubic ramp
229 // fsBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
232 case kFillAA_GrProcessorEdgeType: {
233 SkAssertResult(fsBuilder->enableFeature(
234 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
235 fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", fsName);
236 fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", fsName);
237 fsBuilder->codeAppendf("vec2 gF = vec2(2.0 * %s.x * duvdx.x - duvdx.y,"
238 " 2.0 * %s.x * duvdy.x - duvdy.y);",
240 fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", fsName, fsName, fsName);
241 fsBuilder->codeAppend("edgeAlpha = edgeAlpha / sqrt(dot(gF, gF));");
242 fsBuilder->codeAppend("edgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);");
243 // Add line below for smooth cubic ramp
244 // fsBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
247 case kFillBW_GrProcessorEdgeType: {
248 fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", fsName, fsName, fsName);
249 fsBuilder->codeAppend("edgeAlpha = float(edgeAlpha < 0.0);");
253 SkFAIL("Shouldn't get here");
256 fsBuilder->codeAppendf("%s = %s;", outputColor,
257 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
260 void GrGLQuadEffect::GenKey(const GrProcessor& processor, const GrGLCaps&,
261 GrProcessorKeyBuilder* b) {
262 const GrQuadEffect& ce = processor.cast<GrQuadEffect>();
263 uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
267 //////////////////////////////////////////////////////////////////////////////
269 GrQuadEffect::~GrQuadEffect() {}
271 const GrBackendGeometryProcessorFactory& GrQuadEffect::getFactory() const {
272 return GrTBackendGeometryProcessorFactory<GrQuadEffect>::getInstance();
275 GrQuadEffect::GrQuadEffect(GrPrimitiveEdgeType edgeType)
276 : fEdgeType(edgeType)
277 , fInHairQuadEdge(this->addVertexAttrib(GrShaderVar("inCubicCoeffs",
279 GrShaderVar::kAttribute_TypeModifier))) {
282 bool GrQuadEffect::onIsEqual(const GrProcessor& other) const {
283 const GrQuadEffect& ce = other.cast<GrQuadEffect>();
284 return (ce.fEdgeType == fEdgeType);
287 //////////////////////////////////////////////////////////////////////////////
289 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrQuadEffect);
291 GrGeometryProcessor* GrQuadEffect::TestCreate(SkRandom* random,
293 const GrDrawTargetCaps& caps,
295 GrGeometryProcessor* gp;
297 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
298 random->nextULessThan(kGrProcessorEdgeTypeCnt));
299 gp = GrQuadEffect::Create(edgeType, caps);
300 } while (NULL == gp);
304 //////////////////////////////////////////////////////////////////////////////
306 //////////////////////////////////////////////////////////////////////////////
308 class GrGLCubicEffect : public GrGLGeometryProcessor {
310 GrGLCubicEffect(const GrBackendProcessorFactory&, const GrProcessor&);
312 virtual void emitCode(GrGLFullProgramBuilder* builder,
313 const GrGeometryProcessor& geometryProcessor,
314 const GrProcessorKey& key,
315 const char* outputColor,
316 const char* inputColor,
317 const TransformedCoordsArray&,
318 const TextureSamplerArray&) SK_OVERRIDE;
320 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*);
322 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
325 GrPrimitiveEdgeType fEdgeType;
327 typedef GrGLGeometryProcessor INHERITED;
330 GrGLCubicEffect::GrGLCubicEffect(const GrBackendProcessorFactory& factory,
331 const GrProcessor& processor)
332 : INHERITED (factory) {
333 const GrCubicEffect& ce = processor.cast<GrCubicEffect>();
334 fEdgeType = ce.getEdgeType();
337 void GrGLCubicEffect::emitCode(GrGLFullProgramBuilder* builder,
338 const GrGeometryProcessor& geometryProcessor,
339 const GrProcessorKey& key,
340 const char* outputColor,
341 const char* inputColor,
342 const TransformedCoordsArray&,
343 const TextureSamplerArray& samplers) {
344 const char *vsName, *fsName;
346 builder->addVarying(kVec4f_GrSLType, "CubicCoeffs",
347 &vsName, &fsName, GrGLShaderVar::kHigh_Precision);
349 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
350 const GrShaderVar& inCubicCoeffs = geometryProcessor.cast<GrCubicEffect>().inCubicCoeffs();
351 vsBuilder->codeAppendf("%s = %s;", vsName, inCubicCoeffs.c_str());
353 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
355 GrGLShaderVar edgeAlpha("edgeAlpha", kFloat_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
356 GrGLShaderVar dklmdx("dklmdx", kVec3f_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
357 GrGLShaderVar dklmdy("dklmdy", kVec3f_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
358 GrGLShaderVar dfdx("dfdx", kFloat_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
359 GrGLShaderVar dfdy("dfdy", kFloat_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
360 GrGLShaderVar gF("gF", kVec2f_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
361 GrGLShaderVar gFM("gFM", kFloat_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
362 GrGLShaderVar func("func", kFloat_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
364 fsBuilder->declAppend(edgeAlpha);
365 fsBuilder->declAppend(dklmdx);
366 fsBuilder->declAppend(dklmdy);
367 fsBuilder->declAppend(dfdx);
368 fsBuilder->declAppend(dfdy);
369 fsBuilder->declAppend(gF);
370 fsBuilder->declAppend(gFM);
371 fsBuilder->declAppend(func);
374 case kHairlineAA_GrProcessorEdgeType: {
375 SkAssertResult(fsBuilder->enableFeature(
376 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
377 fsBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), fsName);
378 fsBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), fsName);
379 fsBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
380 dfdx.c_str(), fsName, fsName, dklmdx.c_str(), fsName,
381 dklmdx.c_str(), fsName, dklmdx.c_str());
382 fsBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
383 dfdy.c_str(), fsName, fsName, dklmdy.c_str(), fsName,
384 dklmdy.c_str(), fsName, dklmdy.c_str());
385 fsBuilder->codeAppendf("%s = vec2(%s, %s);", gF.c_str(), dfdx.c_str(), dfdy.c_str());
386 fsBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", gFM.c_str(), gF.c_str(), gF.c_str());
387 fsBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;",
388 func.c_str(), fsName, fsName, fsName, fsName, fsName);
389 fsBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str());
390 fsBuilder->codeAppendf("%s = %s / %s;",
391 edgeAlpha.c_str(), func.c_str(), gFM.c_str());
392 fsBuilder->codeAppendf("%s = max(1.0 - %s, 0.0);",
393 edgeAlpha.c_str(), edgeAlpha.c_str());
394 // Add line below for smooth cubic ramp
395 // fsBuilder->codeAppendf("%s = %s * %s * (3.0 - 2.0 * %s);",
396 // edgeAlpha.c_str(), edgeAlpha.c_str(), edgeAlpha.c_str(),
397 // edgeAlpha.c_str());
400 case kFillAA_GrProcessorEdgeType: {
401 SkAssertResult(fsBuilder->enableFeature(
402 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
403 fsBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), fsName);
404 fsBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), fsName);
405 fsBuilder->codeAppendf("%s ="
406 "3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
407 dfdx.c_str(), fsName, fsName, dklmdx.c_str(), fsName,
408 dklmdx.c_str(), fsName, dklmdx.c_str());
409 fsBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
410 dfdy.c_str(), fsName, fsName, dklmdy.c_str(), fsName,
411 dklmdy.c_str(), fsName, dklmdy.c_str());
412 fsBuilder->codeAppendf("%s = vec2(%s, %s);", gF.c_str(), dfdx.c_str(), dfdy.c_str());
413 fsBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", gFM.c_str(), gF.c_str(), gF.c_str());
414 fsBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;",
415 func.c_str(), fsName, fsName, fsName, fsName, fsName);
416 fsBuilder->codeAppendf("%s = %s / %s;",
417 edgeAlpha.c_str(), func.c_str(), gFM.c_str());
418 fsBuilder->codeAppendf("%s = clamp(1.0 - %s, 0.0, 1.0);",
419 edgeAlpha.c_str(), edgeAlpha.c_str());
420 // Add line below for smooth cubic ramp
421 // fsBuilder->codeAppendf("%s = %s * %s * (3.0 - 2.0 * %s);",
422 // edgeAlpha.c_str(), edgeAlpha.c_str(), edgeAlpha.c_str(),
423 // edgeAlpha.c_str());
426 case kFillBW_GrProcessorEdgeType: {
427 fsBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;",
428 edgeAlpha.c_str(), fsName, fsName, fsName, fsName, fsName);
429 fsBuilder->codeAppendf("%s = float(%s < 0.0);", edgeAlpha.c_str(), edgeAlpha.c_str());
433 SkFAIL("Shouldn't get here");
436 fsBuilder->codeAppendf("%s = %s;", outputColor,
437 (GrGLSLExpr4(inputColor) * GrGLSLExpr1(edgeAlpha.c_str())).c_str());
440 void GrGLCubicEffect::GenKey(const GrProcessor& processor, const GrGLCaps&,
441 GrProcessorKeyBuilder* b) {
442 const GrCubicEffect& ce = processor.cast<GrCubicEffect>();
443 uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2;
447 //////////////////////////////////////////////////////////////////////////////
449 GrCubicEffect::~GrCubicEffect() {}
451 const GrBackendGeometryProcessorFactory& GrCubicEffect::getFactory() const {
452 return GrTBackendGeometryProcessorFactory<GrCubicEffect>::getInstance();
455 GrCubicEffect::GrCubicEffect(GrPrimitiveEdgeType edgeType)
456 : fEdgeType(edgeType)
457 , fInCubicCoeffs(this->addVertexAttrib(GrShaderVar("inCubicCoeffs",
459 GrShaderVar::kAttribute_TypeModifier))) {
462 bool GrCubicEffect::onIsEqual(const GrProcessor& other) const {
463 const GrCubicEffect& ce = other.cast<GrCubicEffect>();
464 return (ce.fEdgeType == fEdgeType);
467 //////////////////////////////////////////////////////////////////////////////
469 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrCubicEffect);
471 GrGeometryProcessor* GrCubicEffect::TestCreate(SkRandom* random,
473 const GrDrawTargetCaps& caps,
475 GrGeometryProcessor* gp;
477 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
478 random->nextULessThan(kGrProcessorEdgeTypeCnt));
479 gp = GrCubicEffect::Create(edgeType, caps);
480 } while (NULL == gp);