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