Home | History | Annotate | Download | only in bench
      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:
     33     PathBench(Flags flags) : fFlags(flags) {
     34         fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style :
     35                         SkPaint::kFill_Style);
     36         fPaint.setStrokeWidth(SkIntToScalar(5));
     37         fPaint.setStrokeJoin(SkPaint::kBevel_Join);
     38     }
     39 
     40     virtual void appendName(SkString*) = 0;
     41     virtual void makePath(SkPath*) = 0;
     42     virtual int complexity() { return 0; }
     43 
     44 protected:
     45     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 
     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:
     82     TrianglePathBench(Flags flags) : INHERITED(flags) {}
     83 
     84     virtual void appendName(SkString* name) SK_OVERRIDE {
     85         name->append("triangle");
     86     }
     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:
    102     RectPathBench(Flags flags) : INHERITED(flags) {}
    103 
    104     virtual void appendName(SkString* name) SK_OVERRIDE {
    105         name->append("rect");
    106     }
    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:
    117     OvalPathBench(Flags flags) : INHERITED(flags) {}
    118 
    119     virtual void appendName(SkString* name) SK_OVERRIDE {
    120         name->append("oval");
    121     }
    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:
    132     CirclePathBench(Flags flags) : INHERITED(flags) {}
    133 
    134     virtual void appendName(SkString* name) SK_OVERRIDE {
    135         name->append("circle");
    136     }
    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:
    147     SawToothPathBench(Flags flags) : INHERITED(flags) {}
    148 
    149     virtual void appendName(SkString* name) SK_OVERRIDE {
    150         name->append("sawtooth");
    151     }
    152     virtual void makePath(SkPath* path) {
    153         SkScalar x = SkIntToScalar(20);
    154         SkScalar y = SkIntToScalar(20);
    155         const SkScalar x0 = x;
    156         const SkScalar dx = SK_Scalar1 * 5;
    157         const SkScalar dy = SK_Scalar1 * 10;
    158 
    159         path->moveTo(x, y);
    160         for (int i = 0; i < 32; i++) {
    161             x += dx;
    162             path->lineTo(x, y - dy);
    163             x += dx;
    164             path->lineTo(x, y + dy);
    165         }
    166         path->lineTo(x, y + 2 * dy);
    167         path->lineTo(x0, y + 2 * dy);
    168         path->close();
    169     }
    170     virtual int complexity() SK_OVERRIDE { return 1; }
    171 private:
    172     typedef PathBench INHERITED;
    173 };
    174 
    175 class LongCurvedPathBench : public PathBench {
    176 public:
    177     LongCurvedPathBench(Flags flags) : INHERITED(flags) {}
    178 
    179     virtual void appendName(SkString* name) SK_OVERRIDE {
    180         name->append("long_curved");
    181     }
    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     }
    193     virtual int complexity() SK_OVERRIDE { return 2; }
    194 private:
    195     typedef PathBench INHERITED;
    196 };
    197 
    198 class LongLinePathBench : public PathBench {
    199 public:
    200     LongLinePathBench(Flags flags) : INHERITED(flags) {}
    201 
    202     virtual void appendName(SkString* name) SK_OVERRIDE {
    203         name->append("long_line");
    204     }
    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     }
    212     virtual int complexity() SK_OVERRIDE { return 2; }
    213 private:
    214     typedef PathBench INHERITED;
    215 };
    216 
    217 class RandomPathBench : public SkBenchmark {
    218 public:
    219     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
    220         return backend == kNonRendering_Backend;
    221     }
    222 
    223 protected:
    224     void createData(int minVerbs,
    225                     int maxVerbs,
    226                     bool allowMoves = true,
    227                     SkRect* bounds = NULL) {
    228         SkRect tempBounds;
    229         if (NULL == bounds) {
    230             tempBounds.setXYWH(0, 0, SK_Scalar1, SK_Scalar1);
    231             bounds = &tempBounds;
    232         }
    233         fVerbCnts.reset(kNumVerbCnts);
    234         for (int i = 0; i < kNumVerbCnts; ++i) {
    235             fVerbCnts[i] = fRandom.nextRangeU(minVerbs, maxVerbs + 1);
    236         }
    237         fVerbs.reset(kNumVerbs);
    238         for (int i = 0; i < kNumVerbs; ++i) {
    239             do {
    240                 fVerbs[i] = static_cast<SkPath::Verb>(fRandom.nextULessThan(SkPath::kDone_Verb));
    241             } while (!allowMoves && SkPath::kMove_Verb == fVerbs[i]);
    242         }
    243         fPoints.reset(kNumPoints);
    244         for (int i = 0; i < kNumPoints; ++i) {
    245             fPoints[i].set(fRandom.nextRangeScalar(bounds->fLeft, bounds->fRight),
    246                            fRandom.nextRangeScalar(bounds->fTop, bounds->fBottom));
    247         }
    248         this->restartMakingPaths();
    249     }
    250 
    251     void restartMakingPaths() {
    252         fCurrPath = 0;
    253         fCurrVerb = 0;
    254         fCurrPoint = 0;
    255     }
    256 
    257     void makePath(SkPath* path) {
    258         int vCount = fVerbCnts[(fCurrPath++) & (kNumVerbCnts - 1)];
    259         for (int v = 0; v < vCount; ++v) {
    260             int verb = fVerbs[(fCurrVerb++) & (kNumVerbs - 1)];
    261             switch (verb) {
    262                 case SkPath::kMove_Verb:
    263                     path->moveTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
    264                     break;
    265                 case SkPath::kLine_Verb:
    266                     path->lineTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
    267                     break;
    268                 case SkPath::kQuad_Verb:
    269                     path->quadTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
    270                                  fPoints[(fCurrPoint + 1) & (kNumPoints - 1)]);
    271                     fCurrPoint += 2;
    272                     break;
    273                 case SkPath::kConic_Verb:
    274                     path->conicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
    275                                   fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
    276                                   SK_ScalarHalf);
    277                     fCurrPoint += 2;
    278                     break;
    279                 case SkPath::kCubic_Verb:
    280                     path->cubicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
    281                                   fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
    282                                   fPoints[(fCurrPoint + 2) & (kNumPoints - 1)]);
    283                     fCurrPoint += 3;
    284                     break;
    285                 case SkPath::kClose_Verb:
    286                     path->close();
    287                     break;
    288                 default:
    289                     SkDEBUGFAIL("Unexpected path verb");
    290                     break;
    291             }
    292         }
    293     }
    294 
    295     void finishedMakingPaths() {
    296         fVerbCnts.reset(0);
    297         fVerbs.reset(0);
    298         fPoints.reset(0);
    299     }
    300 
    301 private:
    302     enum {
    303         // these should all be pow 2
    304         kNumVerbCnts = 1 << 5,
    305         kNumVerbs    = 1 << 5,
    306         kNumPoints   = 1 << 5,
    307     };
    308     SkAutoTArray<int>           fVerbCnts;
    309     SkAutoTArray<SkPath::Verb>  fVerbs;
    310     SkAutoTArray<SkPoint>       fPoints;
    311     int                         fCurrPath;
    312     int                         fCurrVerb;
    313     int                         fCurrPoint;
    314     SkRandom                    fRandom;
    315     typedef SkBenchmark INHERITED;
    316 };
    317 
    318 class PathCreateBench : public RandomPathBench {
    319 public:
    320     PathCreateBench()  {
    321     }
    322 
    323 protected:
    324     virtual const char* onGetName() SK_OVERRIDE {
    325         return "path_create";
    326     }
    327 
    328     virtual void onPreDraw() SK_OVERRIDE {
    329         this->createData(10, 100);
    330         fPaths.reset(kPathCnt);
    331     }
    332 
    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 
    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:
    357     PathCopyBench()  {
    358     }
    359 
    360 protected:
    361     virtual const char* onGetName() SK_OVERRIDE {
    362         return "path_copy";
    363     }
    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     }
    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     }
    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:
    397     PathTransformBench(bool inPlace) : fInPlace(inPlace) {}
    398 
    399 protected:
    400     virtual const char* onGetName() SK_OVERRIDE {
    401         return fInPlace ? "path_transform_in_place" : "path_transform_copy";
    402     }
    403 
    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 
    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 
    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:
    450     PathEqualityBench() { }
    451 
    452 protected:
    453     virtual const char* onGetName() SK_OVERRIDE {
    454         return "path_equality_50%";
    455     }
    456 
    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 
    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 
    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 
    502     SkBench_AddPathTest(AddType type) : fType(type) {
    503         fMatrix.setRotate(60 * SK_Scalar1);
    504     }
    505 
    506 protected:
    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 
    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 
    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 
    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:
    602     CirclesBench(Flags flags) : fFlags(flags) {
    603         fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill");
    604     }
    605 
    606 protected:
    607     virtual const char* onGetName() SK_OVERRIDE {
    608         return fName.c_str();
    609     }
    610 
    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:
    662     ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) {
    663         if (zeroRad) {
    664             fName.printf("zeroradroundrect");
    665         } else {
    666             fName.printf("arbroundrect");
    667         }
    668     }
    669 
    670 protected:
    671     virtual const char* onGetName() SK_OVERRIDE {
    672         return fName.c_str();
    673     }
    674 
    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 
    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 
    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 
    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 
    782     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
    783         return backend == kNonRendering_Backend;
    784     }
    785 
    786 private:
    787     virtual const char* onGetName() SK_OVERRIDE {
    788         return fName.c_str();
    789     }
    790 
    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 
    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 
    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:
    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:
    850     virtual const char* onGetName() SK_OVERRIDE {
    851         return "ratquad-chop-0.5";
    852     }
    853 
    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:
    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:
    875     virtual const char* onGetName() SK_OVERRIDE {
    876         return "ratquad-chop-half";
    877     }
    878 
    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 
    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:
    904     ConicBench()  {
    905         SkRandom rand;
    906         for (int i = 0; i < CONICS; ++i) {
    907             rand_conic(&fConics[i], rand);
    908         }
    909     }
    910 
    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:
    927     ConicBench_ComputeError()  {}
    928 
    929 protected:
    930     virtual const char* onGetName() SK_OVERRIDE {
    931         return "conic-compute-error";
    932     }
    933 
    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:
    949     ConicBench_asQuadTol()  {}
    950 
    951 protected:
    952     virtual const char* onGetName() SK_OVERRIDE {
    953         return "conic-asQuadTol";
    954     }
    955 
    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:
    970     ConicBench_quadPow2()  {}
    971 
    972 protected:
    973     virtual const char* onGetName() SK_OVERRIDE {
    974         return "conic-quadPow2";
    975     }
    976 
    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