Create GLSLUniformHandler class for gpu backend
[platform/upstream/libSkiaSharp.git] / bench / PathBench.cpp
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "Benchmark.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkColorPriv.h"
12 #include "SkPaint.h"
13 #include "SkPath.h"
14 #include "SkRandom.h"
15 #include "SkShader.h"
16 #include "SkString.h"
17 #include "SkTArray.h"
18
19 enum Flags {
20     kStroke_Flag = 1 << 0,
21     kBig_Flag    = 1 << 1
22 };
23
24 #define FLAGS00  Flags(0)
25 #define FLAGS01  Flags(kStroke_Flag)
26 #define FLAGS10  Flags(kBig_Flag)
27 #define FLAGS11  Flags(kStroke_Flag | kBig_Flag)
28
29 class PathBench : public Benchmark {
30     SkPaint     fPaint;
31     SkString    fName;
32     Flags       fFlags;
33 public:
34     PathBench(Flags flags) : fFlags(flags) {
35         fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style :
36                         SkPaint::kFill_Style);
37         fPaint.setStrokeWidth(SkIntToScalar(5));
38         fPaint.setStrokeJoin(SkPaint::kBevel_Join);
39     }
40
41     virtual void appendName(SkString*) = 0;
42     virtual void makePath(SkPath*) = 0;
43     virtual int complexity() { return 0; }
44
45 protected:
46     const char* onGetName() override {
47         fName.printf("path_%s_%s_",
48                      fFlags & kStroke_Flag ? "stroke" : "fill",
49                      fFlags & kBig_Flag ? "big" : "small");
50         this->appendName(&fName);
51         return fName.c_str();
52     }
53
54     void onDraw(int loops, SkCanvas* canvas) override {
55         SkPaint paint(fPaint);
56         this->setupPaint(&paint);
57
58         SkPath path;
59         this->makePath(&path);
60         if (fFlags & kBig_Flag) {
61             const SkMatrix m = SkMatrix::MakeScale(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     void makePath(SkPath* path) override {
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 = nullptr) {
228         SkRect tempBounds;
229         if (nullptr == 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 onDelayedSetup() override {
329         this->createData(10, 100);
330     }
331
332     void onDraw(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 onDelayedSetup() 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(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 onDelayedSetup() 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(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 onDelayedSetup() 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(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 onDelayedSetup() 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(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(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(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(nullptr));
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(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 onDelayedSetup() 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_Chop : public Benchmark {
810 protected:
811     SkConic fRQ, fDst[2];
812     SkString fName;
813 public:
814     ConicBench_Chop() : fName("conic-chop") {
815         fRQ.fPts[0].set(0, 0);
816         fRQ.fPts[1].set(100, 0);
817         fRQ.fPts[2].set(100, 100);
818         fRQ.fW = SkScalarCos(SK_ScalarPI/4);
819     }
820
821     bool isSuitableFor(Backend backend) override {
822         return backend == kNonRendering_Backend;
823     }
824
825 private:
826     const char* onGetName() override { return fName.c_str(); }
827
828     void onDraw(int loops, SkCanvas*) override {
829         for (int i = 0; i < loops; ++i) {
830             fRQ.chop(fDst);
831         }
832     }
833
834     typedef Benchmark INHERITED;
835 };
836 DEF_BENCH( return new ConicBench_Chop; )
837
838 class ConicBench_EvalPos : public ConicBench_Chop {
839     const bool fUseV2;
840 public:
841     ConicBench_EvalPos(bool useV2) : fUseV2(useV2) {
842         fName.printf("conic-eval-pos%d", useV2);
843     }
844     void onDraw(int loops, SkCanvas*) override {
845         if (fUseV2) {
846             for (int i = 0; i < loops; ++i) {
847                 for (int j = 0; j < 1000; ++j) {
848                     fDst[0].fPts[0] = fRQ.evalAt(0.4f);
849                 }
850             }
851         } else {
852             for (int i = 0; i < loops; ++i) {
853                 for (int j = 0; j < 1000; ++j) {
854                     fRQ.evalAt(0.4f, &fDst[0].fPts[0], nullptr);
855                 }
856             }
857         }
858     }
859 };
860 DEF_BENCH( return new ConicBench_EvalPos(false); )
861 DEF_BENCH( return new ConicBench_EvalPos(true); )
862
863 class ConicBench_EvalTan : public ConicBench_Chop {
864     const bool fUseV2;
865 public:
866     ConicBench_EvalTan(bool useV2) : fUseV2(useV2) {
867         fName.printf("conic-eval-tan%d", useV2);
868     }
869     void onDraw(int loops, SkCanvas*) override {
870         if (fUseV2) {
871             for (int i = 0; i < loops; ++i) {
872                 for (int j = 0; j < 1000; ++j) {
873                     fDst[0].fPts[0] = fRQ.evalTangentAt(0.4f);
874                 }
875             }
876         } else {
877             for (int i = 0; i < loops; ++i) {
878                 for (int j = 0; j < 1000; ++j) {
879                     fRQ.evalAt(0.4f, nullptr, &fDst[0].fPts[0]);
880                 }
881             }
882         }
883     }
884 };
885 DEF_BENCH( return new ConicBench_EvalTan(false); )
886 DEF_BENCH( return new ConicBench_EvalTan(true); )
887
888 ///////////////////////////////////////////////////////////////////////////////
889
890 static void rand_conic(SkConic* conic, SkRandom& rand) {
891     for (int i = 0; i < 3; ++i) {
892         conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100);
893     }
894     if (rand.nextUScalar1() > 0.5f) {
895         conic->fW = rand.nextUScalar1();
896     } else {
897         conic->fW = 1 + rand.nextUScalar1() * 4;
898     }
899 }
900
901 class ConicBench : public Benchmark {
902 public:
903     ConicBench()  {
904         SkRandom rand;
905         for (int i = 0; i < CONICS; ++i) {
906             rand_conic(&fConics[i], rand);
907         }
908     }
909
910     bool isSuitableFor(Backend backend) override {
911         return backend == kNonRendering_Backend;
912     }
913
914 protected:
915     enum {
916         CONICS = 100
917     };
918     SkConic fConics[CONICS];
919
920 private:
921     typedef Benchmark INHERITED;
922 };
923
924 class ConicBench_ComputeError : public ConicBench {
925 public:
926     ConicBench_ComputeError()  {}
927
928 protected:
929     const char* onGetName() override {
930         return "conic-compute-error";
931     }
932
933     void onDraw(int loops, SkCanvas*) override {
934         SkVector err;
935         for (int i = 0; i < loops; ++i) {
936             for (int j = 0; j < CONICS; ++j) {
937                 fConics[j].computeAsQuadError(&err);
938             }
939         }
940     }
941
942 private:
943     typedef ConicBench INHERITED;
944 };
945
946 class ConicBench_asQuadTol : public ConicBench {
947 public:
948     ConicBench_asQuadTol()  {}
949
950 protected:
951     const char* onGetName() override {
952         return "conic-asQuadTol";
953     }
954
955     void onDraw(int loops, SkCanvas*) override {
956         for (int i = 0; i < loops; ++i) {
957             for (int j = 0; j < CONICS; ++j) {
958                 fConics[j].asQuadTol(SK_ScalarHalf);
959             }
960         }
961     }
962
963 private:
964     typedef ConicBench INHERITED;
965 };
966
967 class ConicBench_quadPow2 : public ConicBench {
968 public:
969     ConicBench_quadPow2()  {}
970
971 protected:
972     const char* onGetName() override {
973         return "conic-quadPow2";
974     }
975
976     void onDraw(int loops, SkCanvas*) override {
977         for (int i = 0; i < loops; ++i) {
978             for (int j = 0; j < CONICS; ++j) {
979                 fConics[j].computeQuadPOW2(SK_ScalarHalf);
980             }
981         }
982     }
983
984 private:
985     typedef ConicBench INHERITED;
986 };
987
988 ///////////////////////////////////////////////////////////////////////////////
989
990 const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
991 const SkSize ConservativelyContainsBench::kQueryMin = SkSize::Make(SkIntToScalar(1), SkIntToScalar(1));
992 const SkSize ConservativelyContainsBench::kQueryMax = SkSize::Make(SkIntToScalar(40), SkIntToScalar(40));
993 const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50));
994 const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)};
995
996 DEF_BENCH( return new TrianglePathBench(FLAGS00); )
997 DEF_BENCH( return new TrianglePathBench(FLAGS01); )
998 DEF_BENCH( return new TrianglePathBench(FLAGS10); )
999 DEF_BENCH( return new TrianglePathBench(FLAGS11); )
1000
1001 DEF_BENCH( return new RectPathBench(FLAGS00); )
1002 DEF_BENCH( return new RectPathBench(FLAGS01); )
1003 DEF_BENCH( return new RectPathBench(FLAGS10); )
1004 DEF_BENCH( return new RectPathBench(FLAGS11); )
1005
1006 DEF_BENCH( return new OvalPathBench(FLAGS00); )
1007 DEF_BENCH( return new OvalPathBench(FLAGS01); )
1008 DEF_BENCH( return new OvalPathBench(FLAGS10); )
1009 DEF_BENCH( return new OvalPathBench(FLAGS11); )
1010
1011 DEF_BENCH( return new CirclePathBench(FLAGS00); )
1012 DEF_BENCH( return new CirclePathBench(FLAGS01); )
1013 DEF_BENCH( return new CirclePathBench(FLAGS10); )
1014 DEF_BENCH( return new CirclePathBench(FLAGS11); )
1015
1016 DEF_BENCH( return new SawToothPathBench(FLAGS00); )
1017 DEF_BENCH( return new SawToothPathBench(FLAGS01); )
1018
1019 DEF_BENCH( return new LongCurvedPathBench(FLAGS00); )
1020 DEF_BENCH( return new LongCurvedPathBench(FLAGS01); )
1021 DEF_BENCH( return new LongLinePathBench(FLAGS00); )
1022 DEF_BENCH( return new LongLinePathBench(FLAGS01); )
1023
1024 DEF_BENCH( return new PathCreateBench(); )
1025 DEF_BENCH( return new PathCopyBench(); )
1026 DEF_BENCH( return new PathTransformBench(true); )
1027 DEF_BENCH( return new PathTransformBench(false); )
1028 DEF_BENCH( return new PathEqualityBench(); )
1029
1030 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); )
1031 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); )
1032 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); )
1033 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); )
1034 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); )
1035
1036 DEF_BENCH( return new CirclesBench(FLAGS00); )
1037 DEF_BENCH( return new CirclesBench(FLAGS01); )
1038 DEF_BENCH( return new ArbRoundRectBench(false); )
1039 DEF_BENCH( return new ArbRoundRectBench(true); )
1040 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); )
1041 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); )
1042 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); )
1043
1044
1045 // These seem to be optimized away, which is troublesome for timing.
1046 /*
1047 DEF_BENCH( return new ConicBench_Chop5() )
1048 DEF_BENCH( return new ConicBench_ComputeError() )
1049 DEF_BENCH( return new ConicBench_asQuadTol() )
1050 DEF_BENCH( return new ConicBench_quadPow2() )
1051 */