Home | History | Annotate | Download | only in effects
      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 "GrBezierEffect.h"
      9 #include "GrShaderCaps.h"
     10 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     11 #include "glsl/GrGLSLGeometryProcessor.h"
     12 #include "glsl/GrGLSLProgramDataManager.h"
     13 #include "glsl/GrGLSLUniformHandler.h"
     14 #include "glsl/GrGLSLUtil.h"
     15 #include "glsl/GrGLSLVarying.h"
     16 #include "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 
     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 
     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 
     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", kFloat_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 = %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 = %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 = %s.x * %s.x - %s.y * %s.z;",
    184                                      edgeAlpha.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
    185             fragBuilder->codeAppendf("%s = float(%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(%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 
    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 
    222 GrConicEffect::~GrConicEffect() {}
    223 
    224 void GrConicEffect::getGLSLProcessorKey(const GrShaderCaps& caps,
    225                                         GrProcessorKeyBuilder* b) const {
    226     GrGLConicEffect::GenKey(*this, caps, b);
    227 }
    228 
    229 GrGLSLPrimitiveProcessor* GrConicEffect::createGLSLInstance(const GrShaderCaps&) const {
    230     return new GrGLConicEffect(*this);
    231 }
    232 
    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
    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 
    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 
    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 
    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 = dFdx(%s.xy);", v.fsIn());
    358             fragBuilder->codeAppendf("half2 duvdy = 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 = (%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 = dFdx(%s.xy);", v.fsIn());
    372             fragBuilder->codeAppendf("half2 duvdy = 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 = (%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 = (%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 
    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 
    422 GrQuadEffect::~GrQuadEffect() {}
    423 
    424 void GrQuadEffect::getGLSLProcessorKey(const GrShaderCaps& caps,
    425                                        GrProcessorKeyBuilder* b) const {
    426     GrGLQuadEffect::GenKey(*this, caps, b);
    427 }
    428 
    429 GrGLSLPrimitiveProcessor* GrQuadEffect::createGLSLInstance(const GrShaderCaps&) const {
    430     return new GrGLQuadEffect(*this);
    431 }
    432 
    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
    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