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