Home | History | Annotate | Download | only in gm
      1 
      2 /*
      3  * Copyright 2013 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 // This test only works with the GPU backend.
     10 
     11 #include "gm.h"
     12 
     13 #if SK_SUPPORT_GPU
     14 
     15 #include "GrDrawContext.h"
     16 #include "GrContext.h"
     17 #include "GrPathUtils.h"
     18 #include "GrTest.h"
     19 #include "SkColorPriv.h"
     20 #include "SkDevice.h"
     21 #include "SkGeometry.h"
     22 
     23 #include "batches/GrTestBatch.h"
     24 
     25 #include "effects/GrBezierEffect.h"
     26 
     27 static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
     28     return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
     29 }
     30 
     31 namespace skiagm {
     32 
     33 class BezierCubicOrConicTestBatch : public GrTestBatch {
     34 public:
     35     DEFINE_BATCH_CLASS_ID
     36     struct Geometry : public GrTestBatch::Geometry {
     37         SkRect fBounds;
     38     };
     39 
     40     const char* name() const override { return "BezierCubicOrConicTestBatch"; }
     41 
     42     static GrDrawBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
     43                                const SkScalar klmEqs[9], SkScalar sign) {
     44         return new BezierCubicOrConicTestBatch(gp, geo, klmEqs, sign);
     45     }
     46 
     47 private:
     48     BezierCubicOrConicTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
     49                                 const SkScalar klmEqs[9], SkScalar sign)
     50         : INHERITED(ClassID(), gp, geo.fBounds) {
     51         for (int i = 0; i < 9; i++) {
     52             fKlmEqs[i] = klmEqs[i];
     53         }
     54 
     55         fGeometry = geo;
     56         fSign = sign;
     57     }
     58 
     59     struct Vertex {
     60         SkPoint fPosition;
     61         float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
     62     };
     63 
     64     Geometry* geoData(int index) override {
     65         SkASSERT(0 == index);
     66         return &fGeometry;
     67     }
     68 
     69     const Geometry* geoData(int index) const override {
     70         SkASSERT(0 == index);
     71         return &fGeometry;
     72     }
     73 
     74     void generateGeometry(Target* target) const override {
     75         QuadHelper helper;
     76         size_t vertexStride = this->geometryProcessor()->getVertexStride();
     77         SkASSERT(vertexStride == sizeof(Vertex));
     78         Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
     79         if (!verts) {
     80             return;
     81         }
     82 
     83         verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
     84                                       fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
     85                                       sizeof(Vertex));
     86         for (int v = 0; v < 4; ++v) {
     87             verts[v].fKLM[0] = eval_line(verts[v].fPosition, fKlmEqs + 0, fSign);
     88             verts[v].fKLM[1] = eval_line(verts[v].fPosition, fKlmEqs + 3, fSign);
     89             verts[v].fKLM[2] = eval_line(verts[v].fPosition, fKlmEqs + 6, 1.f);
     90         }
     91         helper.recordDraw(target);
     92     }
     93 
     94     Geometry fGeometry;
     95     SkScalar fKlmEqs[9];
     96     SkScalar fSign;
     97 
     98     static const int kVertsPerCubic = 4;
     99     static const int kIndicesPerCubic = 6;
    100 
    101     typedef GrTestBatch INHERITED;
    102 };
    103 
    104 /**
    105  * This GM directly exercises effects that draw Bezier curves in the GPU backend.
    106  */
    107 class BezierCubicEffects : public GM {
    108 public:
    109     BezierCubicEffects() {
    110         this->setBGColor(0xFFFFFFFF);
    111     }
    112 
    113 protected:
    114     SkString onShortName() override {
    115         return SkString("bezier_cubic_effects");
    116     }
    117 
    118     SkISize onISize() override {
    119         return SkISize::Make(800, 800);
    120     }
    121 
    122     void onDraw(SkCanvas* canvas) override {
    123         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
    124         if (nullptr == rt) {
    125             skiagm::GM::DrawGpuOnlyMessage(canvas);
    126             return;
    127         }
    128         GrContext* context = rt->getContext();
    129         if (nullptr == context) {
    130             return;
    131         }
    132 
    133         SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
    134         if (!drawContext) {
    135             return;
    136         }
    137 
    138         struct Vertex {
    139             SkPoint fPosition;
    140             float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
    141         };
    142 
    143         static const int kNumCubics = 15;
    144         SkRandom rand;
    145 
    146         // Mult by 3 for each edge effect type
    147         int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
    148         int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
    149         SkScalar w = SkIntToScalar(rt->width()) / numCols;
    150         SkScalar h = SkIntToScalar(rt->height()) / numRows;
    151         int row = 0;
    152         int col = 0;
    153         static const GrColor color = 0xff000000;
    154 
    155         for (int i = 0; i < kNumCubics; ++i) {
    156             SkPoint baseControlPts[] = {
    157                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
    158                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
    159                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
    160                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
    161             };
    162             for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
    163                 SkAutoTUnref<GrGeometryProcessor> gp;
    164                 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
    165                 gp.reset(GrCubicEffect::Create(color, SkMatrix::I(), et,
    166                                                *context->caps()));
    167                 if (!gp) {
    168                     continue;
    169                 }
    170                 SkScalar x = SkScalarMul(col, w);
    171                 SkScalar y = SkScalarMul(row, h);
    172                 SkPoint controlPts[] = {
    173                     {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
    174                     {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
    175                     {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
    176                     {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
    177                 };
    178                 SkPoint chopped[10];
    179                 SkScalar klmEqs[9];
    180                 SkScalar klmSigns[3];
    181                 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
    182                                                                    chopped,
    183                                                                    klmEqs,
    184                                                                    klmSigns);
    185 
    186                 SkPaint ctrlPtPaint;
    187                 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
    188                 for (int i = 0; i < 4; ++i) {
    189                     canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
    190                 }
    191 
    192                 SkPaint polyPaint;
    193                 polyPaint.setColor(0xffA0A0A0);
    194                 polyPaint.setStrokeWidth(0);
    195                 polyPaint.setStyle(SkPaint::kStroke_Style);
    196                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
    197 
    198                 SkPaint choppedPtPaint;
    199                 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
    200 
    201                 for (int c = 0; c < cnt; ++c) {
    202                     SkPoint* pts = chopped + 3 * c;
    203 
    204                     for (int i = 0; i < 4; ++i) {
    205                         canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
    206                     }
    207 
    208                     SkRect bounds;
    209                     bounds.set(pts, 4);
    210 
    211                     SkPaint boundsPaint;
    212                     boundsPaint.setColor(0xff808080);
    213                     boundsPaint.setStrokeWidth(0);
    214                     boundsPaint.setStyle(SkPaint::kStroke_Style);
    215                     canvas->drawRect(bounds, boundsPaint);
    216 
    217                     GrPipelineBuilder pipelineBuilder;
    218                     pipelineBuilder.setXPFactory(
    219                         GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
    220                     pipelineBuilder.setRenderTarget(rt);
    221 
    222                     BezierCubicOrConicTestBatch::Geometry geometry;
    223                     geometry.fColor = color;
    224                     geometry.fBounds = bounds;
    225 
    226                     SkAutoTUnref<GrDrawBatch> batch(
    227                             BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
    228 
    229                     drawContext->internal_drawBatch(pipelineBuilder, batch);
    230                 }
    231                 ++col;
    232                 if (numCols == col) {
    233                     col = 0;
    234                     ++row;
    235                 }
    236             }
    237         }
    238     }
    239 
    240 private:
    241     typedef GM INHERITED;
    242 };
    243 
    244 //////////////////////////////////////////////////////////////////////////////
    245 
    246 /**
    247  * This GM directly exercises effects that draw Bezier curves in the GPU backend.
    248  */
    249 class BezierConicEffects : public GM {
    250 public:
    251     BezierConicEffects() {
    252         this->setBGColor(0xFFFFFFFF);
    253     }
    254 
    255 protected:
    256     SkString onShortName() override {
    257         return SkString("bezier_conic_effects");
    258     }
    259 
    260     SkISize onISize() override {
    261         return SkISize::Make(800, 800);
    262     }
    263 
    264 
    265     void onDraw(SkCanvas* canvas) override {
    266         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
    267         if (nullptr == rt) {
    268             skiagm::GM::DrawGpuOnlyMessage(canvas);
    269             return;
    270         }
    271         GrContext* context = rt->getContext();
    272         if (nullptr == context) {
    273             return;
    274         }
    275 
    276         SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
    277         if (!drawContext) {
    278             return;
    279         }
    280 
    281         struct Vertex {
    282             SkPoint fPosition;
    283             float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
    284         };
    285 
    286         static const int kNumConics = 10;
    287         SkRandom rand;
    288 
    289         // Mult by 3 for each edge effect type
    290         int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
    291         int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
    292         SkScalar w = SkIntToScalar(rt->width()) / numCols;
    293         SkScalar h = SkIntToScalar(rt->height()) / numRows;
    294         int row = 0;
    295         int col = 0;
    296         static const GrColor color = 0xff000000;
    297 
    298         for (int i = 0; i < kNumConics; ++i) {
    299             SkPoint baseControlPts[] = {
    300                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
    301                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
    302                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
    303             };
    304             SkScalar weight = rand.nextRangeF(0.f, 2.f);
    305             for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
    306                 SkAutoTUnref<GrGeometryProcessor> gp;
    307                 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
    308                 gp.reset(GrConicEffect::Create(color, SkMatrix::I(), et,
    309                                                *context->caps(), SkMatrix::I(), false));
    310                 if (!gp) {
    311                     continue;
    312                 }
    313 
    314                 SkScalar x = SkScalarMul(col, w);
    315                 SkScalar y = SkScalarMul(row, h);
    316                 SkPoint controlPts[] = {
    317                     {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
    318                     {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
    319                     {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
    320                 };
    321                 SkConic dst[4];
    322                 SkScalar klmEqs[9];
    323                 int cnt = chop_conic(controlPts, dst, weight);
    324                 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
    325 
    326                 SkPaint ctrlPtPaint;
    327                 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
    328                 for (int i = 0; i < 3; ++i) {
    329                     canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
    330                 }
    331 
    332                 SkPaint polyPaint;
    333                 polyPaint.setColor(0xffA0A0A0);
    334                 polyPaint.setStrokeWidth(0);
    335                 polyPaint.setStyle(SkPaint::kStroke_Style);
    336                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
    337 
    338                 SkPaint choppedPtPaint;
    339                 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
    340 
    341                 for (int c = 0; c < cnt; ++c) {
    342                     SkPoint* pts = dst[c].fPts;
    343                     for (int i = 0; i < 3; ++i) {
    344                         canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
    345                     }
    346 
    347                     SkRect bounds;
    348                     //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
    349                     //bounds.set(bPts, 2);
    350                     bounds.set(pts, 3);
    351 
    352                     SkPaint boundsPaint;
    353                     boundsPaint.setColor(0xff808080);
    354                     boundsPaint.setStrokeWidth(0);
    355                     boundsPaint.setStyle(SkPaint::kStroke_Style);
    356                     canvas->drawRect(bounds, boundsPaint);
    357 
    358                     GrPipelineBuilder pipelineBuilder;
    359                     pipelineBuilder.setXPFactory(
    360                         GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
    361                     pipelineBuilder.setRenderTarget(rt);
    362 
    363                     BezierCubicOrConicTestBatch::Geometry geometry;
    364                     geometry.fColor = color;
    365                     geometry.fBounds = bounds;
    366 
    367                     SkAutoTUnref<GrDrawBatch> batch(
    368                             BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
    369 
    370                     drawContext->internal_drawBatch(pipelineBuilder, batch);
    371                 }
    372                 ++col;
    373                 if (numCols == col) {
    374                     col = 0;
    375                     ++row;
    376                 }
    377             }
    378         }
    379     }
    380 
    381 private:
    382     // Uses the max curvature function for quads to estimate
    383     // where to chop the conic. If the max curvature is not
    384     // found along the curve segment it will return 1 and
    385     // dst[0] is the original conic. If it returns 2 the dst[0]
    386     // and dst[1] are the two new conics.
    387     int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
    388         SkScalar t = SkFindQuadMaxCurvature(src);
    389         if (t == 0) {
    390             if (dst) {
    391                 dst[0].set(src, weight);
    392             }
    393             return 1;
    394         } else {
    395             if (dst) {
    396                 SkConic conic;
    397                 conic.set(src, weight);
    398                 conic.chopAt(t, dst);
    399             }
    400             return 2;
    401         }
    402     }
    403 
    404     // Calls split_conic on the entire conic and then once more on each subsection.
    405     // Most cases will result in either 1 conic (chop point is not within t range)
    406     // or 3 points (split once and then one subsection is split again).
    407     int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
    408         SkConic dstTemp[2];
    409         int conicCnt = split_conic(src, dstTemp, weight);
    410         if (2 == conicCnt) {
    411             int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
    412             conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
    413         } else {
    414             dst[0] = dstTemp[0];
    415         }
    416         return conicCnt;
    417     }
    418 
    419     typedef GM INHERITED;
    420 };
    421 
    422 //////////////////////////////////////////////////////////////////////////////
    423 
    424 class BezierQuadTestBatch : public GrTestBatch {
    425 public:
    426     DEFINE_BATCH_CLASS_ID
    427     struct Geometry : public GrTestBatch::Geometry {
    428         SkRect fBounds;
    429     };
    430 
    431     const char* name() const override { return "BezierQuadTestBatch"; }
    432 
    433     static GrDrawBatch* Create(const GrGeometryProcessor* gp, const Geometry& geo,
    434                                const GrPathUtils::QuadUVMatrix& devToUV) {
    435         return new BezierQuadTestBatch(gp, geo, devToUV);
    436     }
    437 
    438 private:
    439     BezierQuadTestBatch(const GrGeometryProcessor* gp, const Geometry& geo,
    440                         const GrPathUtils::QuadUVMatrix& devToUV)
    441         : INHERITED(ClassID(), gp, geo.fBounds)
    442         , fGeometry(geo)
    443         , fDevToUV(devToUV) {
    444     }
    445 
    446     struct Vertex {
    447         SkPoint fPosition;
    448         float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
    449     };
    450 
    451     Geometry* geoData(int index) override {
    452         SkASSERT(0 == index);
    453         return &fGeometry;
    454     }
    455 
    456     const Geometry* geoData(int index) const override {
    457         SkASSERT(0 == index);
    458         return &fGeometry;
    459     }
    460 
    461     void generateGeometry(Target* target) const override {
    462         QuadHelper helper;
    463         size_t vertexStride = this->geometryProcessor()->getVertexStride();
    464         SkASSERT(vertexStride == sizeof(Vertex));
    465         Vertex* verts = reinterpret_cast<Vertex*>(helper.init(target, vertexStride, 1));
    466         if (!verts) {
    467             return;
    468         }
    469         verts[0].fPosition.setRectFan(fGeometry.fBounds.fLeft, fGeometry.fBounds.fTop,
    470                                       fGeometry.fBounds.fRight, fGeometry.fBounds.fBottom,
    471                                       sizeof(Vertex));
    472         fDevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
    473         helper.recordDraw(target);
    474     }
    475 
    476     Geometry fGeometry;
    477     GrPathUtils::QuadUVMatrix fDevToUV;
    478 
    479     static const int kVertsPerCubic = 4;
    480     static const int kIndicesPerCubic = 6;
    481 
    482     typedef GrTestBatch INHERITED;
    483 };
    484 
    485 /**
    486  * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
    487  */
    488 class BezierQuadEffects : public GM {
    489 public:
    490     BezierQuadEffects() {
    491         this->setBGColor(0xFFFFFFFF);
    492     }
    493 
    494 protected:
    495     SkString onShortName() override {
    496         return SkString("bezier_quad_effects");
    497     }
    498 
    499     SkISize onISize() override {
    500         return SkISize::Make(800, 800);
    501     }
    502 
    503 
    504     void onDraw(SkCanvas* canvas) override {
    505         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
    506         if (nullptr == rt) {
    507             skiagm::GM::DrawGpuOnlyMessage(canvas);
    508             return;
    509         }
    510         GrContext* context = rt->getContext();
    511         if (nullptr == context) {
    512             return;
    513         }
    514 
    515         SkAutoTUnref<GrDrawContext> drawContext(context->drawContext(rt));
    516         if (!drawContext) {
    517             return;
    518         }
    519 
    520         struct Vertex {
    521             SkPoint fPosition;
    522             float   fUV[4]; // The last two values are ignored. The effect expects a vec4f.
    523         };
    524 
    525         static const int kNumQuads = 5;
    526         SkRandom rand;
    527 
    528         int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
    529         int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
    530         SkScalar w = SkIntToScalar(rt->width()) / numCols;
    531         SkScalar h = SkIntToScalar(rt->height()) / numRows;
    532         int row = 0;
    533         int col = 0;
    534         static const GrColor color = 0xff000000;
    535 
    536         for (int i = 0; i < kNumQuads; ++i) {
    537             SkPoint baseControlPts[] = {
    538                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
    539                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
    540                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
    541             };
    542             for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
    543                 SkAutoTUnref<GrGeometryProcessor> gp;
    544                 GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
    545                 gp.reset(GrQuadEffect::Create(color, SkMatrix::I(), et,
    546                                               *context->caps(), SkMatrix::I(), false));
    547                 if (!gp) {
    548                     continue;
    549                 }
    550 
    551                 SkScalar x = SkScalarMul(col, w);
    552                 SkScalar y = SkScalarMul(row, h);
    553                 SkPoint controlPts[] = {
    554                     {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
    555                     {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
    556                     {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
    557                 };
    558                 SkPoint chopped[5];
    559                 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
    560 
    561                 SkPaint ctrlPtPaint;
    562                 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
    563                 for (int i = 0; i < 3; ++i) {
    564                     canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
    565                 }
    566 
    567                 SkPaint polyPaint;
    568                 polyPaint.setColor(0xffA0A0A0);
    569                 polyPaint.setStrokeWidth(0);
    570                 polyPaint.setStyle(SkPaint::kStroke_Style);
    571                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
    572 
    573                 SkPaint choppedPtPaint;
    574                 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
    575 
    576                 for (int c = 0; c < cnt; ++c) {
    577                     SkPoint* pts = chopped + 2 * c;
    578 
    579                     for (int i = 0; i < 3; ++i) {
    580                         canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
    581                     }
    582 
    583                     SkRect bounds;
    584                     bounds.set(pts, 3);
    585 
    586                     SkPaint boundsPaint;
    587                     boundsPaint.setColor(0xff808080);
    588                     boundsPaint.setStrokeWidth(0);
    589                     boundsPaint.setStyle(SkPaint::kStroke_Style);
    590                     canvas->drawRect(bounds, boundsPaint);
    591 
    592                     GrPipelineBuilder pipelineBuilder;
    593                     pipelineBuilder.setXPFactory(
    594                         GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref();
    595                     pipelineBuilder.setRenderTarget(rt);
    596 
    597                     GrPathUtils::QuadUVMatrix DevToUV(pts);
    598 
    599                     BezierQuadTestBatch::Geometry geometry;
    600                     geometry.fColor = color;
    601                     geometry.fBounds = bounds;
    602 
    603                     SkAutoTUnref<GrDrawBatch> batch(BezierQuadTestBatch::Create(gp, geometry,
    604                                                                                 DevToUV));
    605 
    606                     drawContext->internal_drawBatch(pipelineBuilder, batch);
    607                 }
    608                 ++col;
    609                 if (numCols == col) {
    610                     col = 0;
    611                     ++row;
    612                 }
    613             }
    614         }
    615     }
    616 
    617 private:
    618     typedef GM INHERITED;
    619 };
    620 
    621 DEF_GM(return new BezierCubicEffects;)
    622 DEF_GM(return new BezierConicEffects;)
    623 DEF_GM(return new BezierQuadEffects;)
    624 }
    625 
    626 #endif
    627