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