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