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