• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
eval_line(const SkPoint & p,const SkScalar lineEq[3],SkScalar sign)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 
name() const40     const char* name() const override { return "BezierCubicOrConicTestBatch"; }
41 
Create(const GrGeometryProcessor * gp,const Geometry & geo,const SkScalar klmEqs[9],SkScalar sign)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:
BezierCubicOrConicTestBatch(const GrGeometryProcessor * gp,const Geometry & geo,const SkScalar klmEqs[9],SkScalar sign)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 
geoData(int index)64     Geometry* geoData(int index) override {
65         SkASSERT(0 == index);
66         return &fGeometry;
67     }
68 
geoData(int index) const69     const Geometry* geoData(int index) const override {
70         SkASSERT(0 == index);
71         return &fGeometry;
72     }
73 
generateGeometry(Target * target) const74     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:
BezierCubicEffects()109     BezierCubicEffects() {
110         this->setBGColor(0xFFFFFFFF);
111     }
112 
113 protected:
onShortName()114     SkString onShortName() override {
115         return SkString("bezier_cubic_effects");
116     }
117 
onISize()118     SkISize onISize() override {
119         return SkISize::Make(800, 800);
120     }
121 
onDraw(SkCanvas * canvas)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:
BezierConicEffects()251     BezierConicEffects() {
252         this->setBGColor(0xFFFFFFFF);
253     }
254 
255 protected:
onShortName()256     SkString onShortName() override {
257         return SkString("bezier_conic_effects");
258     }
259 
onISize()260     SkISize onISize() override {
261         return SkISize::Make(800, 800);
262     }
263 
264 
onDraw(SkCanvas * canvas)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.
split_conic(const SkPoint src[3],SkConic dst[2],const SkScalar weight)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).
chop_conic(const SkPoint src[3],SkConic dst[4],const SkScalar weight)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 
name() const431     const char* name() const override { return "BezierQuadTestBatch"; }
432 
Create(const GrGeometryProcessor * gp,const Geometry & geo,const GrPathUtils::QuadUVMatrix & devToUV)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:
BezierQuadTestBatch(const GrGeometryProcessor * gp,const Geometry & geo,const GrPathUtils::QuadUVMatrix & devToUV)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 
geoData(int index)451     Geometry* geoData(int index) override {
452         SkASSERT(0 == index);
453         return &fGeometry;
454     }
455 
geoData(int index) const456     const Geometry* geoData(int index) const override {
457         SkASSERT(0 == index);
458         return &fGeometry;
459     }
460 
generateGeometry(Target * target) const461     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:
BezierQuadEffects()490     BezierQuadEffects() {
491         this->setBGColor(0xFFFFFFFF);
492     }
493 
494 protected:
onShortName()495     SkString onShortName() override {
496         return SkString("bezier_quad_effects");
497     }
498 
onISize()499     SkISize onISize() override {
500         return SkISize::Make(800, 800);
501     }
502 
503 
onDraw(SkCanvas * canvas)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