C++11 override should now be supported by all of {bots,Chrome,Android,Mozilla}
[platform/upstream/libSkiaSharp.git] / bench / PathBench.cpp
1
2 /*
3  * Copyright 2011 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 #include "Benchmark.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkColorPriv.h"
12 #include "SkPaint.h"
13 #include "SkRandom.h"
14 #include "SkShader.h"
15 #include "SkString.h"
16 #include "SkTArray.h"
17
18 enum Flags {
19     kStroke_Flag = 1 << 0,
20     kBig_Flag    = 1 << 1
21 };
22
23 #define FLAGS00  Flags(0)
24 #define FLAGS01  Flags(kStroke_Flag)
25 #define FLAGS10  Flags(kBig_Flag)
26 #define FLAGS11  Flags(kStroke_Flag | kBig_Flag)
27
28 class PathBench : public Benchmark {
29     SkPaint     fPaint;
30     SkString    fName;
31     Flags       fFlags;
32 public:
33     PathBench(Flags flags) : fFlags(flags) {
34         fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style :
35                         SkPaint::kFill_Style);
36         fPaint.setStrokeWidth(SkIntToScalar(5));
37         fPaint.setStrokeJoin(SkPaint::kBevel_Join);
38     }
39
40     virtual void appendName(SkString*) = 0;
41     virtual void makePath(SkPath*) = 0;
42     virtual int complexity() { return 0; }
43
44 protected:
45     const char* onGetName() override {
46         fName.printf("path_%s_%s_",
47                      fFlags & kStroke_Flag ? "stroke" : "fill",
48                      fFlags & kBig_Flag ? "big" : "small");
49         this->appendName(&fName);
50         return fName.c_str();
51     }
52
53     void onDraw(const int loops, SkCanvas* canvas) override {
54         SkPaint paint(fPaint);
55         this->setupPaint(&paint);
56
57         SkPath path;
58         this->makePath(&path);
59         if (fFlags & kBig_Flag) {
60             SkMatrix m;
61             m.setScale(SkIntToScalar(10), SkIntToScalar(10));
62             path.transform(m);
63         }
64
65         int count = loops;
66         if (fFlags & kBig_Flag) {
67             count >>= 2;
68         }
69         count >>= (3 * complexity());
70
71         for (int i = 0; i < count; i++) {
72             canvas->drawPath(path, paint);
73         }
74     }
75
76 private:
77     typedef Benchmark INHERITED;
78 };
79
80 class TrianglePathBench : public PathBench {
81 public:
82     TrianglePathBench(Flags flags) : INHERITED(flags) {}
83
84     void appendName(SkString* name) override {
85         name->append("triangle");
86     }
87     void makePath(SkPath* path) override {
88         static const int gCoord[] = {
89             10, 10, 15, 5, 20, 20
90         };
91         path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
92         path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
93         path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
94         path->close();
95     }
96 private:
97     typedef PathBench INHERITED;
98 };
99
100 class RectPathBench : public PathBench {
101 public:
102     RectPathBench(Flags flags) : INHERITED(flags) {}
103
104     void appendName(SkString* name) override {
105         name->append("rect");
106     }
107     void makePath(SkPath* path) override {
108         SkRect r = { 10, 10, 20, 20 };
109         path->addRect(r);
110     }
111 private:
112     typedef PathBench INHERITED;
113 };
114
115 class OvalPathBench : public PathBench {
116 public:
117     OvalPathBench(Flags flags) : INHERITED(flags) {}
118
119     void appendName(SkString* name) override {
120         name->append("oval");
121     }
122     void makePath(SkPath* path) override {
123         SkRect r = { 10, 10, 23, 20 };
124         path->addOval(r);
125     }
126 private:
127     typedef PathBench INHERITED;
128 };
129
130 class CirclePathBench: public PathBench {
131 public:
132     CirclePathBench(Flags flags) : INHERITED(flags) {}
133
134     void appendName(SkString* name) override {
135         name->append("circle");
136     }
137     void makePath(SkPath* path) override {
138         path->addCircle(SkIntToScalar(20), SkIntToScalar(20),
139                         SkIntToScalar(10));
140     }
141 private:
142     typedef PathBench INHERITED;
143 };
144
145 class SawToothPathBench : public PathBench {
146 public:
147     SawToothPathBench(Flags flags) : INHERITED(flags) {}
148
149     void appendName(SkString* name) override {
150         name->append("sawtooth");
151     }
152     virtual void makePath(SkPath* path) {
153         SkScalar x = SkIntToScalar(20);
154         SkScalar y = SkIntToScalar(20);
155         const SkScalar x0 = x;
156         const SkScalar dx = SK_Scalar1 * 5;
157         const SkScalar dy = SK_Scalar1 * 10;
158
159         path->moveTo(x, y);
160         for (int i = 0; i < 32; i++) {
161             x += dx;
162             path->lineTo(x, y - dy);
163             x += dx;
164             path->lineTo(x, y + dy);
165         }
166         path->lineTo(x, y + 2 * dy);
167         path->lineTo(x0, y + 2 * dy);
168         path->close();
169     }
170     int complexity() override { return 1; }
171 private:
172     typedef PathBench INHERITED;
173 };
174
175 class LongCurvedPathBench : public PathBench {
176 public:
177     LongCurvedPathBench(Flags flags) : INHERITED(flags) {}
178
179     void appendName(SkString* name) override {
180         name->append("long_curved");
181     }
182     void makePath(SkPath* path) override {
183         SkRandom rand (12);
184         int i;
185         for (i = 0; i < 100; i++) {
186             path->quadTo(SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
187                          SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)),
188                          SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
189                          SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)));
190         }
191         path->close();
192     }
193     int complexity() override { return 2; }
194 private:
195     typedef PathBench INHERITED;
196 };
197
198 class LongLinePathBench : public PathBench {
199 public:
200     LongLinePathBench(Flags flags) : INHERITED(flags) {}
201
202     void appendName(SkString* name) override {
203         name->append("long_line");
204     }
205     void makePath(SkPath* path) override {
206         SkRandom rand;
207         path->moveTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
208         for (size_t i = 1; i < 100; i++) {
209             path->lineTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
210         }
211     }
212     int complexity() override { return 2; }
213 private:
214     typedef PathBench INHERITED;
215 };
216
217 class RandomPathBench : public Benchmark {
218 public:
219     bool isSuitableFor(Backend backend) override {
220         return backend == kNonRendering_Backend;
221     }
222
223 protected:
224     void createData(int minVerbs,
225                     int maxVerbs,
226                     bool allowMoves = true,
227                     SkRect* bounds = NULL) {
228         SkRect tempBounds;
229         if (NULL == bounds) {
230             tempBounds.setXYWH(0, 0, SK_Scalar1, SK_Scalar1);
231             bounds = &tempBounds;
232         }
233         fVerbCnts.reset(kNumVerbCnts);
234         for (int i = 0; i < kNumVerbCnts; ++i) {
235             fVerbCnts[i] = fRandom.nextRangeU(minVerbs, maxVerbs + 1);
236         }
237         fVerbs.reset(kNumVerbs);
238         for (int i = 0; i < kNumVerbs; ++i) {
239             do {
240                 fVerbs[i] = static_cast<SkPath::Verb>(fRandom.nextULessThan(SkPath::kDone_Verb));
241             } while (!allowMoves && SkPath::kMove_Verb == fVerbs[i]);
242         }
243         fPoints.reset(kNumPoints);
244         for (int i = 0; i < kNumPoints; ++i) {
245             fPoints[i].set(fRandom.nextRangeScalar(bounds->fLeft, bounds->fRight),
246                            fRandom.nextRangeScalar(bounds->fTop, bounds->fBottom));
247         }
248         this->restartMakingPaths();
249     }
250
251     void restartMakingPaths() {
252         fCurrPath = 0;
253         fCurrVerb = 0;
254         fCurrPoint = 0;
255     }
256
257     void makePath(SkPath* path) {
258         int vCount = fVerbCnts[(fCurrPath++) & (kNumVerbCnts - 1)];
259         for (int v = 0; v < vCount; ++v) {
260             int verb = fVerbs[(fCurrVerb++) & (kNumVerbs - 1)];
261             switch (verb) {
262                 case SkPath::kMove_Verb:
263                     path->moveTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
264                     break;
265                 case SkPath::kLine_Verb:
266                     path->lineTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
267                     break;
268                 case SkPath::kQuad_Verb:
269                     path->quadTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
270                                  fPoints[(fCurrPoint + 1) & (kNumPoints - 1)]);
271                     fCurrPoint += 2;
272                     break;
273                 case SkPath::kConic_Verb:
274                     path->conicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
275                                   fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
276                                   SK_ScalarHalf);
277                     fCurrPoint += 2;
278                     break;
279                 case SkPath::kCubic_Verb:
280                     path->cubicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
281                                   fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
282                                   fPoints[(fCurrPoint + 2) & (kNumPoints - 1)]);
283                     fCurrPoint += 3;
284                     break;
285                 case SkPath::kClose_Verb:
286                     path->close();
287                     break;
288                 default:
289                     SkDEBUGFAIL("Unexpected path verb");
290                     break;
291             }
292         }
293     }
294
295     void finishedMakingPaths() {
296         fVerbCnts.reset(0);
297         fVerbs.reset(0);
298         fPoints.reset(0);
299     }
300
301 private:
302     enum {
303         // these should all be pow 2
304         kNumVerbCnts = 1 << 5,
305         kNumVerbs    = 1 << 5,
306         kNumPoints   = 1 << 5,
307     };
308     SkAutoTArray<int>           fVerbCnts;
309     SkAutoTArray<SkPath::Verb>  fVerbs;
310     SkAutoTArray<SkPoint>       fPoints;
311     int                         fCurrPath;
312     int                         fCurrVerb;
313     int                         fCurrPoint;
314     SkRandom                    fRandom;
315     typedef Benchmark INHERITED;
316 };
317
318 class PathCreateBench : public RandomPathBench {
319 public:
320     PathCreateBench()  {
321     }
322
323 protected:
324     const char* onGetName() override {
325         return "path_create";
326     }
327
328     void onPreDraw() override {
329         this->createData(10, 100);
330     }
331
332     void onDraw(const int loops, SkCanvas*) override {
333         for (int i = 0; i < loops; ++i) {
334             if (i % 1000 == 0) {
335                 fPath.reset();  // PathRef memory can grow without bound otherwise.
336             }
337             this->makePath(&fPath);
338         }
339         this->restartMakingPaths();
340     }
341
342 private:
343     SkPath fPath;
344
345     typedef RandomPathBench INHERITED;
346 };
347
348 class PathCopyBench : public RandomPathBench {
349 public:
350     PathCopyBench()  {
351     }
352
353 protected:
354     const char* onGetName() override {
355         return "path_copy";
356     }
357     void onPreDraw() override {
358         this->createData(10, 100);
359         fPaths.reset(kPathCnt);
360         fCopies.reset(kPathCnt);
361         for (int i = 0; i < kPathCnt; ++i) {
362             this->makePath(&fPaths[i]);
363         }
364         this->finishedMakingPaths();
365     }
366     void onDraw(const int loops, SkCanvas*) override {
367         for (int i = 0; i < loops; ++i) {
368             int idx = i & (kPathCnt - 1);
369             fCopies[idx] = fPaths[idx];
370         }
371     }
372
373 private:
374     enum {
375         // must be a pow 2
376         kPathCnt = 1 << 5,
377     };
378     SkAutoTArray<SkPath> fPaths;
379     SkAutoTArray<SkPath> fCopies;
380
381     typedef RandomPathBench INHERITED;
382 };
383
384 class PathTransformBench : public RandomPathBench {
385 public:
386     PathTransformBench(bool inPlace) : fInPlace(inPlace) {}
387
388 protected:
389     const char* onGetName() override {
390         return fInPlace ? "path_transform_in_place" : "path_transform_copy";
391     }
392
393     void onPreDraw() override {
394         fMatrix.setScale(5 * SK_Scalar1, 6 * SK_Scalar1);
395         this->createData(10, 100);
396         fPaths.reset(kPathCnt);
397         for (int i = 0; i < kPathCnt; ++i) {
398             this->makePath(&fPaths[i]);
399         }
400         this->finishedMakingPaths();
401         if (!fInPlace) {
402             fTransformed.reset(kPathCnt);
403         }
404     }
405
406     void onDraw(const int loops, SkCanvas*) override {
407         if (fInPlace) {
408             for (int i = 0; i < loops; ++i) {
409                 fPaths[i & (kPathCnt - 1)].transform(fMatrix);
410             }
411         } else {
412             for (int i = 0; i < loops; ++i) {
413                 int idx = i & (kPathCnt - 1);
414                 fPaths[idx].transform(fMatrix, &fTransformed[idx]);
415             }
416         }
417     }
418
419 private:
420     enum {
421         // must be a pow 2
422         kPathCnt = 1 << 5,
423     };
424     SkAutoTArray<SkPath> fPaths;
425     SkAutoTArray<SkPath> fTransformed;
426
427     SkMatrix fMatrix;
428     bool fInPlace;
429     typedef RandomPathBench INHERITED;
430 };
431
432 class PathEqualityBench : public RandomPathBench {
433 public:
434     PathEqualityBench() { }
435
436 protected:
437     const char* onGetName() override {
438         return "path_equality_50%";
439     }
440
441     void onPreDraw() override {
442         fParity = 0;
443         this->createData(10, 100);
444         fPaths.reset(kPathCnt);
445         fCopies.reset(kPathCnt);
446         for (int i = 0; i < kPathCnt; ++i) {
447             this->makePath(&fPaths[i]);
448             fCopies[i] = fPaths[i];
449         }
450         this->finishedMakingPaths();
451     }
452
453     void onDraw(const int loops, SkCanvas*) override {
454         for (int i = 0; i < loops; ++i) {
455             int idx = i & (kPathCnt - 1);
456             fParity ^= (fPaths[idx] == fCopies[idx & ~0x1]);
457         }
458     }
459
460 private:
461     bool fParity; // attempt to keep compiler from optimizing out the ==
462     enum {
463         // must be a pow 2
464         kPathCnt = 1 << 5,
465     };
466     SkAutoTArray<SkPath> fPaths;
467     SkAutoTArray<SkPath> fCopies;
468     typedef RandomPathBench INHERITED;
469 };
470
471 class SkBench_AddPathTest : public RandomPathBench {
472 public:
473     enum AddType {
474         kAdd_AddType,
475         kAddTrans_AddType,
476         kAddMatrix_AddType,
477         kReverseAdd_AddType,
478         kReversePathTo_AddType,
479     };
480
481     SkBench_AddPathTest(AddType type) : fType(type) {
482         fMatrix.setRotate(60 * SK_Scalar1);
483     }
484
485 protected:
486     const char* onGetName() override {
487         switch (fType) {
488             case kAdd_AddType:
489                 return "path_add_path";
490             case kAddTrans_AddType:
491                 return "path_add_path_trans";
492             case kAddMatrix_AddType:
493                 return "path_add_path_matrix";
494             case kReverseAdd_AddType:
495                 return "path_reverse_add_path";
496             case kReversePathTo_AddType:
497                 return "path_reverse_path_to";
498             default:
499                 SkDEBUGFAIL("Bad add type");
500                 return "";
501         }
502     }
503
504     void onPreDraw() override {
505         // reversePathTo assumes a single contour path.
506         bool allowMoves = kReversePathTo_AddType != fType;
507         this->createData(10, 100, allowMoves);
508         fPaths0.reset(kPathCnt);
509         fPaths1.reset(kPathCnt);
510         for (int i = 0; i < kPathCnt; ++i) {
511             this->makePath(&fPaths0[i]);
512             this->makePath(&fPaths1[i]);
513         }
514         this->finishedMakingPaths();
515     }
516
517     void onDraw(const int loops, SkCanvas*) override {
518         switch (fType) {
519             case kAdd_AddType:
520                 for (int i = 0; i < loops; ++i) {
521                     int idx = i & (kPathCnt - 1);
522                     SkPath result = fPaths0[idx];
523                     result.addPath(fPaths1[idx]);
524                 }
525                 break;
526             case kAddTrans_AddType:
527                 for (int i = 0; i < loops; ++i) {
528                     int idx = i & (kPathCnt - 1);
529                     SkPath result = fPaths0[idx];
530                     result.addPath(fPaths1[idx], 2 * SK_Scalar1, 5 * SK_Scalar1);
531                 }
532                 break;
533             case kAddMatrix_AddType:
534                 for (int i = 0; i < loops; ++i) {
535                     int idx = i & (kPathCnt - 1);
536                     SkPath result = fPaths0[idx];
537                     result.addPath(fPaths1[idx], fMatrix);
538                 }
539                 break;
540             case kReverseAdd_AddType:
541                 for (int i = 0; i < loops; ++i) {
542                     int idx = i & (kPathCnt - 1);
543                     SkPath result = fPaths0[idx];
544                     result.reverseAddPath(fPaths1[idx]);
545                 }
546                 break;
547             case kReversePathTo_AddType:
548                 for (int i = 0; i < loops; ++i) {
549                     int idx = i & (kPathCnt - 1);
550                     SkPath result = fPaths0[idx];
551                     result.reversePathTo(fPaths1[idx]);
552                 }
553                 break;
554         }
555     }
556
557 private:
558     AddType fType; // or reverseAddPath
559     enum {
560         // must be a pow 2
561         kPathCnt = 1 << 5,
562     };
563     SkAutoTArray<SkPath> fPaths0;
564     SkAutoTArray<SkPath> fPaths1;
565     SkMatrix         fMatrix;
566     typedef RandomPathBench INHERITED;
567 };
568
569
570 class CirclesBench : public Benchmark {
571 protected:
572     SkString            fName;
573     Flags               fFlags;
574
575 public:
576     CirclesBench(Flags flags) : fFlags(flags) {
577         fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill");
578     }
579
580 protected:
581     const char* onGetName() override {
582         return fName.c_str();
583     }
584
585     void onDraw(const int loops, SkCanvas* canvas) override {
586         SkPaint paint;
587
588         paint.setColor(SK_ColorBLACK);
589         paint.setAntiAlias(true);
590         if (fFlags & kStroke_Flag) {
591             paint.setStyle(SkPaint::kStroke_Style);
592         }
593
594         SkRandom rand;
595
596         SkRect r;
597
598         for (int i = 0; i < loops; ++i) {
599             SkScalar radius = rand.nextUScalar1() * 3;
600             r.fLeft = rand.nextUScalar1() * 300;
601             r.fTop =  rand.nextUScalar1() * 300;
602             r.fRight =  r.fLeft + 2 * radius;
603             r.fBottom = r.fTop + 2 * radius;
604
605             if (fFlags & kStroke_Flag) {
606                 paint.setStrokeWidth(rand.nextUScalar1() * 5.0f);
607             }
608
609             SkPath temp;
610
611             // mimic how Chrome does circles
612             temp.arcTo(r, 0, 0, false);
613             temp.addOval(r, SkPath::kCCW_Direction);
614             temp.arcTo(r, 360, 0, true);
615             temp.close();
616
617             canvas->drawPath(temp, paint);
618         }
619     }
620
621 private:
622     typedef Benchmark INHERITED;
623 };
624
625
626 // Chrome creates its own round rects with each corner possibly being different.
627 // In its "zero radius" incarnation it creates degenerate round rects.
628 // Note: PathTest::test_arb_round_rect_is_convex and
629 // test_arb_zero_rad_round_rect_is_rect perform almost exactly
630 // the same test (but with no drawing)
631 class ArbRoundRectBench : public Benchmark {
632 protected:
633     SkString            fName;
634
635 public:
636     ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) {
637         if (zeroRad) {
638             fName.printf("zeroradroundrect");
639         } else {
640             fName.printf("arbroundrect");
641         }
642     }
643
644 protected:
645     const char* onGetName() override {
646         return fName.c_str();
647     }
648
649     static void add_corner_arc(SkPath* path, const SkRect& rect,
650                                SkScalar xIn, SkScalar yIn,
651                                int startAngle)
652     {
653
654         SkScalar rx = SkMinScalar(rect.width(), xIn);
655         SkScalar ry = SkMinScalar(rect.height(), yIn);
656
657         SkRect arcRect;
658         arcRect.set(-rx, -ry, rx, ry);
659         switch (startAngle) {
660         case 0:
661             arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom);
662             break;
663         case 90:
664             arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom);
665             break;
666         case 180:
667             arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop);
668             break;
669         case 270:
670             arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop);
671             break;
672         default:
673             break;
674         }
675
676         path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false);
677     }
678
679     static void make_arb_round_rect(SkPath* path, const SkRect& r,
680                                     SkScalar xCorner, SkScalar yCorner) {
681         // we are lazy here and use the same x & y for each corner
682         add_corner_arc(path, r, xCorner, yCorner, 270);
683         add_corner_arc(path, r, xCorner, yCorner, 0);
684         add_corner_arc(path, r, xCorner, yCorner, 90);
685         add_corner_arc(path, r, xCorner, yCorner, 180);
686         path->close();
687
688         SkASSERT(path->isConvex());
689     }
690
691     void onDraw(const int loops, SkCanvas* canvas) override {
692         SkRandom rand;
693         SkRect r;
694
695         for (int i = 0; i < loops; ++i) {
696             SkPaint paint;
697             paint.setColor(0xff000000 | rand.nextU());
698             paint.setAntiAlias(true);
699
700             SkScalar size = rand.nextUScalar1() * 30;
701             if (size < SK_Scalar1) {
702                 continue;
703             }
704             r.fLeft = rand.nextUScalar1() * 300;
705             r.fTop =  rand.nextUScalar1() * 300;
706             r.fRight =  r.fLeft + 2 * size;
707             r.fBottom = r.fTop + 2 * size;
708
709             SkPath temp;
710
711             if (fZeroRad) {
712                 make_arb_round_rect(&temp, r, 0, 0);
713
714                 SkASSERT(temp.isRect(NULL));
715             } else {
716                 make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
717             }
718
719             canvas->drawPath(temp, paint);
720         }
721     }
722
723 private:
724     bool fZeroRad;      // should 0 radius rounds rects be tested?
725
726     typedef Benchmark INHERITED;
727 };
728
729 class ConservativelyContainsBench : public Benchmark {
730 public:
731     enum Type {
732         kRect_Type,
733         kRoundRect_Type,
734         kOval_Type,
735     };
736
737     ConservativelyContainsBench(Type type)  {
738         fParity = false;
739         fName = "conservatively_contains_";
740         switch (type) {
741             case kRect_Type:
742                 fName.append("rect");
743                 fPath.addRect(kBaseRect);
744                 break;
745             case kRoundRect_Type:
746                 fName.append("round_rect");
747                 fPath.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1]);
748                 break;
749             case kOval_Type:
750                 fName.append("oval");
751                 fPath.addOval(kBaseRect);
752                 break;
753         }
754     }
755
756     bool isSuitableFor(Backend backend) override {
757         return backend == kNonRendering_Backend;
758     }
759
760 private:
761     const char* onGetName() override {
762         return fName.c_str();
763     }
764
765     void onDraw(const int loops, SkCanvas*) override {
766         for (int i = 0; i < loops; ++i) {
767             const SkRect& rect = fQueryRects[i % kQueryRectCnt];
768             fParity = fParity != fPath.conservativelyContainsRect(rect);
769         }
770     }
771
772     void onPreDraw() override {
773         fQueryRects.setCount(kQueryRectCnt);
774
775         SkRandom rand;
776         for (int i = 0; i < kQueryRectCnt; ++i) {
777             SkSize size;
778             SkPoint xy;
779             size.fWidth = rand.nextRangeScalar(kQueryMin.fWidth,  kQueryMax.fWidth);
780             size.fHeight = rand.nextRangeScalar(kQueryMin.fHeight, kQueryMax.fHeight);
781             xy.fX = rand.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth);
782             xy.fY = rand.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight);
783
784             fQueryRects[i] = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight);
785         }
786     }
787
788     enum {
789         kQueryRectCnt = 400,
790     };
791     static const SkRect kBounds;   // bounds for all random query rects
792     static const SkSize kQueryMin; // minimum query rect size, should be <= kQueryMax
793     static const SkSize kQueryMax; // max query rect size, should < kBounds
794     static const SkRect kBaseRect; // rect that is used to construct the path
795     static const SkScalar kRRRadii[2]; // x and y radii for round rect
796
797     SkString            fName;
798     SkPath              fPath;
799     bool                fParity;
800     SkTDArray<SkRect>   fQueryRects;
801
802     typedef Benchmark INHERITED;
803 };
804
805 ///////////////////////////////////////////////////////////////////////////////
806
807 #include "SkGeometry.h"
808
809 class ConicBench_Chop5 : public Benchmark {
810     SkConic fRQ;
811 public:
812     ConicBench_Chop5()  {
813         fRQ.fPts[0].set(0, 0);
814         fRQ.fPts[1].set(100, 0);
815         fRQ.fPts[2].set(100, 100);
816         fRQ.fW = SkScalarCos(SK_ScalarPI/4);
817     }
818
819 private:
820     const char* onGetName() override {
821         return "ratquad-chop-0.5";
822     }
823
824     void onDraw(const int loops, SkCanvas*) override {
825         SkConic dst[2];
826         for (int i = 0; i < loops; ++i) {
827             fRQ.chopAt(0.5f, dst);
828         }
829     }
830
831     typedef Benchmark INHERITED;
832 };
833
834 class ConicBench_ChopHalf : public Benchmark {
835 protected:
836     SkConic fRQ, fDst[2];
837     SkString fName;
838     const bool fUseV2;
839 public:
840     ConicBench_ChopHalf(bool useV2) : fUseV2(useV2) {
841         fRQ.fPts[0].set(0, 0);
842         fRQ.fPts[1].set(100, 0);
843         fRQ.fPts[2].set(100, 100);
844         fRQ.fW = SkScalarCos(SK_ScalarPI/4);
845
846         fName.printf("conic-chop-half%d", useV2);
847     }
848
849     bool isSuitableFor(Backend backend) override {
850         return backend == kNonRendering_Backend;
851     }
852
853 private:
854     const char* onGetName() override { return fName.c_str(); }
855
856     void onDraw(const int loops, SkCanvas*) override {
857         if (fUseV2) {
858             for (int i = 0; i < loops; ++i) {
859                 fRQ.chop2(fDst);
860             }
861         } else {
862             for (int i = 0; i < loops; ++i) {
863                 fRQ.chop(fDst);
864             }
865         }
866     }
867
868     typedef Benchmark INHERITED;
869 };
870 DEF_BENCH( return new ConicBench_ChopHalf(false); )
871 DEF_BENCH( return new ConicBench_ChopHalf(true); )
872
873 class ConicBench_EvalPos : public ConicBench_ChopHalf {
874 public:
875     ConicBench_EvalPos(bool useV2) : ConicBench_ChopHalf(useV2) {
876         fName.printf("conic-eval-pos%d", useV2);
877     }
878     void onDraw(const int loops, SkCanvas*) override {
879         if (fUseV2) {
880             for (int i = 0; i < loops; ++i) {
881                 for (int j = 0; j < 1000; ++j) {
882                     fDst[0].fPts[0] = fRQ.evalAt(0.4f);
883                 }
884             }
885         } else {
886             for (int i = 0; i < loops; ++i) {
887                 for (int j = 0; j < 1000; ++j) {
888                     fRQ.evalAt(0.4f, &fDst[0].fPts[0], NULL);
889                 }
890             }
891         }
892     }
893 };
894 DEF_BENCH( return new ConicBench_EvalPos(false); )
895 DEF_BENCH( return new ConicBench_EvalPos(true); )
896
897 class ConicBench_EvalTan : public ConicBench_ChopHalf {
898 public:
899     ConicBench_EvalTan(bool useV2) : ConicBench_ChopHalf(useV2) {
900         fName.printf("conic-eval-tan%d", useV2);
901     }
902     void onDraw(const int loops, SkCanvas*) override {
903         if (fUseV2) {
904             for (int i = 0; i < loops; ++i) {
905                 for (int j = 0; j < 1000; ++j) {
906                     fDst[0].fPts[0] = fRQ.evalTangentAt(0.4f);
907                 }
908             }
909         } else {
910             for (int i = 0; i < loops; ++i) {
911                 for (int j = 0; j < 1000; ++j) {
912                     fRQ.evalAt(0.4f, NULL, &fDst[0].fPts[0]);
913                 }
914             }
915         }
916     }
917 };
918 DEF_BENCH( return new ConicBench_EvalTan(false); )
919 DEF_BENCH( return new ConicBench_EvalTan(true); )
920
921 ///////////////////////////////////////////////////////////////////////////////
922
923 static void rand_conic(SkConic* conic, SkRandom& rand) {
924     for (int i = 0; i < 3; ++i) {
925         conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100);
926     }
927     if (rand.nextUScalar1() > 0.5f) {
928         conic->fW = rand.nextUScalar1();
929     } else {
930         conic->fW = 1 + rand.nextUScalar1() * 4;
931     }
932 }
933
934 class ConicBench : public Benchmark {
935 public:
936     ConicBench()  {
937         SkRandom rand;
938         for (int i = 0; i < CONICS; ++i) {
939             rand_conic(&fConics[i], rand);
940         }
941     }
942
943     bool isSuitableFor(Backend backend) override {
944         return backend == kNonRendering_Backend;
945     }
946
947 protected:
948     enum {
949         CONICS = 100
950     };
951     SkConic fConics[CONICS];
952
953 private:
954     typedef Benchmark INHERITED;
955 };
956
957 class ConicBench_ComputeError : public ConicBench {
958 public:
959     ConicBench_ComputeError()  {}
960
961 protected:
962     const char* onGetName() override {
963         return "conic-compute-error";
964     }
965
966     void onDraw(const int loops, SkCanvas*) override {
967         SkVector err;
968         for (int i = 0; i < loops; ++i) {
969             for (int j = 0; j < CONICS; ++j) {
970                 fConics[j].computeAsQuadError(&err);
971             }
972         }
973     }
974
975 private:
976     typedef ConicBench INHERITED;
977 };
978
979 class ConicBench_asQuadTol : public ConicBench {
980 public:
981     ConicBench_asQuadTol()  {}
982
983 protected:
984     const char* onGetName() override {
985         return "conic-asQuadTol";
986     }
987
988     void onDraw(const int loops, SkCanvas*) override {
989         for (int i = 0; i < loops; ++i) {
990             for (int j = 0; j < CONICS; ++j) {
991                 fConics[j].asQuadTol(SK_ScalarHalf);
992             }
993         }
994     }
995
996 private:
997     typedef ConicBench INHERITED;
998 };
999
1000 class ConicBench_quadPow2 : public ConicBench {
1001 public:
1002     ConicBench_quadPow2()  {}
1003
1004 protected:
1005     const char* onGetName() override {
1006         return "conic-quadPow2";
1007     }
1008
1009     void onDraw(const int loops, SkCanvas*) override {
1010         for (int i = 0; i < loops; ++i) {
1011             for (int j = 0; j < CONICS; ++j) {
1012                 fConics[j].computeQuadPOW2(SK_ScalarHalf);
1013             }
1014         }
1015     }
1016
1017 private:
1018     typedef ConicBench INHERITED;
1019 };
1020
1021 ///////////////////////////////////////////////////////////////////////////////
1022
1023 const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
1024 const SkSize ConservativelyContainsBench::kQueryMin = SkSize::Make(SkIntToScalar(1), SkIntToScalar(1));
1025 const SkSize ConservativelyContainsBench::kQueryMax = SkSize::Make(SkIntToScalar(40), SkIntToScalar(40));
1026 const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50));
1027 const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)};
1028
1029 DEF_BENCH( return new TrianglePathBench(FLAGS00); )
1030 DEF_BENCH( return new TrianglePathBench(FLAGS01); )
1031 DEF_BENCH( return new TrianglePathBench(FLAGS10); )
1032 DEF_BENCH( return new TrianglePathBench(FLAGS11); )
1033
1034 DEF_BENCH( return new RectPathBench(FLAGS00); )
1035 DEF_BENCH( return new RectPathBench(FLAGS01); )
1036 DEF_BENCH( return new RectPathBench(FLAGS10); )
1037 DEF_BENCH( return new RectPathBench(FLAGS11); )
1038
1039 DEF_BENCH( return new OvalPathBench(FLAGS00); )
1040 DEF_BENCH( return new OvalPathBench(FLAGS01); )
1041 DEF_BENCH( return new OvalPathBench(FLAGS10); )
1042 DEF_BENCH( return new OvalPathBench(FLAGS11); )
1043
1044 DEF_BENCH( return new CirclePathBench(FLAGS00); )
1045 DEF_BENCH( return new CirclePathBench(FLAGS01); )
1046 DEF_BENCH( return new CirclePathBench(FLAGS10); )
1047 DEF_BENCH( return new CirclePathBench(FLAGS11); )
1048
1049 DEF_BENCH( return new SawToothPathBench(FLAGS00); )
1050 DEF_BENCH( return new SawToothPathBench(FLAGS01); )
1051
1052 DEF_BENCH( return new LongCurvedPathBench(FLAGS00); )
1053 DEF_BENCH( return new LongCurvedPathBench(FLAGS01); )
1054 DEF_BENCH( return new LongLinePathBench(FLAGS00); )
1055 DEF_BENCH( return new LongLinePathBench(FLAGS01); )
1056
1057 DEF_BENCH( return new PathCreateBench(); )
1058 DEF_BENCH( return new PathCopyBench(); )
1059 DEF_BENCH( return new PathTransformBench(true); )
1060 DEF_BENCH( return new PathTransformBench(false); )
1061 DEF_BENCH( return new PathEqualityBench(); )
1062
1063 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); )
1064 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); )
1065 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); )
1066 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); )
1067 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); )
1068
1069 DEF_BENCH( return new CirclesBench(FLAGS00); )
1070 DEF_BENCH( return new CirclesBench(FLAGS01); )
1071 DEF_BENCH( return new ArbRoundRectBench(false); )
1072 DEF_BENCH( return new ArbRoundRectBench(true); )
1073 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); )
1074 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); )
1075 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); )
1076
1077
1078 // These seem to be optimized away, which is troublesome for timing.
1079 /*
1080 DEF_BENCH( return new ConicBench_Chop5() )
1081 DEF_BENCH( return new ConicBench_ComputeError() )
1082 DEF_BENCH( return new ConicBench_asQuadTol() )
1083 DEF_BENCH( return new ConicBench_quadPow2() )
1084 */