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