Home | History | Annotate | Download | only in bench
      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 "SkAAClip.h"
     10 #include "SkCanvas.h"
     11 #include "SkPath.h"
     12 #include "SkRandom.h"
     13 #include "SkRegion.h"
     14 #include "SkString.h"
     15 #include "SkClipOpPriv.h"
     16 
     17 ////////////////////////////////////////////////////////////////////////////////
     18 // This bench tests out AA/BW clipping via canvas' clipPath and clipRect calls
     19 class AAClipBench : public Benchmark {
     20     SkString fName;
     21     SkPath   fClipPath;
     22     SkRect   fClipRect;
     23     SkRect   fDrawRect;
     24     bool     fDoPath;
     25     bool     fDoAA;
     26 
     27 public:
     28     AAClipBench(bool doPath, bool doAA)
     29         : fDoPath(doPath)
     30         , fDoAA(doAA) {
     31 
     32         fName.printf("aaclip_%s_%s",
     33                      doPath ? "path" : "rect",
     34                      doAA ? "AA" : "BW");
     35 
     36         fClipRect.set(10.5f, 10.5f,
     37                       50.5f, 50.5f);
     38         fClipPath.addRoundRect(fClipRect, SkIntToScalar(10), SkIntToScalar(10));
     39         fDrawRect.set(SkIntToScalar(0), SkIntToScalar(0),
     40                       SkIntToScalar(100), SkIntToScalar(100));
     41 
     42         SkASSERT(fClipPath.isConvex());
     43     }
     44 
     45 protected:
     46     virtual const char* onGetName() { return fName.c_str(); }
     47     virtual void onDraw(int loops, SkCanvas* canvas) {
     48 
     49         SkPaint paint;
     50         this->setupPaint(&paint);
     51 
     52         for (int i = 0; i < loops; ++i) {
     53             // jostle the clip regions each time to prevent caching
     54             fClipRect.offset((i % 2) == 0 ? SkIntToScalar(10) : SkIntToScalar(-10), 0);
     55             fClipPath.reset();
     56             fClipPath.addRoundRect(fClipRect,
     57                                    SkIntToScalar(5), SkIntToScalar(5));
     58             SkASSERT(fClipPath.isConvex());
     59 
     60             canvas->save();
     61 #if 1
     62             if (fDoPath) {
     63                 canvas->clipPath(fClipPath, kReplace_SkClipOp, fDoAA);
     64             } else {
     65                 canvas->clipRect(fClipRect, kReplace_SkClipOp, fDoAA);
     66             }
     67 
     68             canvas->drawRect(fDrawRect, paint);
     69 #else
     70             // this path tests out directly draw the clip primitive
     71             // use it to comparing just drawing the clip vs. drawing using
     72             // the clip
     73             if (fDoPath) {
     74                 canvas->drawPath(fClipPath, paint);
     75             } else {
     76                 canvas->drawRect(fClipRect, paint);
     77             }
     78 #endif
     79             canvas->restore();
     80         }
     81     }
     82 private:
     83     typedef Benchmark INHERITED;
     84 };
     85 
     86 ////////////////////////////////////////////////////////////////////////////////
     87 // This bench tests out nested clip stacks. It is intended to simulate
     88 // how WebKit nests clips.
     89 class NestedAAClipBench : public Benchmark {
     90     SkString fName;
     91     bool     fDoAA;
     92     SkRect   fDrawRect;
     93     SkRandom fRandom;
     94 
     95     static const int kNestingDepth = 3;
     96     static const int kImageSize = 400;
     97 
     98     SkPoint fSizes[kNestingDepth+1];
     99 
    100 public:
    101     NestedAAClipBench(bool doAA) : fDoAA(doAA) {
    102         fName.printf("nested_aaclip_%s", doAA ? "AA" : "BW");
    103 
    104         fDrawRect = SkRect::MakeLTRB(0, 0,
    105                                      SkIntToScalar(kImageSize),
    106                                      SkIntToScalar(kImageSize));
    107 
    108         fSizes[0].set(SkIntToScalar(kImageSize), SkIntToScalar(kImageSize));
    109 
    110         for (int i = 1; i < kNestingDepth+1; ++i) {
    111             fSizes[i].set(fSizes[i-1].fX/2, fSizes[i-1].fY/2);
    112         }
    113     }
    114 
    115 protected:
    116     virtual const char* onGetName() { return fName.c_str(); }
    117 
    118 
    119     void recurse(SkCanvas* canvas,
    120                  int depth,
    121                  const SkPoint& offset) {
    122 
    123             canvas->save();
    124 
    125             SkRect temp = SkRect::MakeLTRB(0, 0,
    126                                            fSizes[depth].fX, fSizes[depth].fY);
    127             temp.offset(offset);
    128 
    129             SkPath path;
    130             path.addRoundRect(temp, SkIntToScalar(3), SkIntToScalar(3));
    131             SkASSERT(path.isConvex());
    132 
    133             canvas->clipPath(path,
    134                              0 == depth ? kReplace_SkClipOp : kIntersect_SkClipOp,
    135                              fDoAA);
    136 
    137             if (kNestingDepth == depth) {
    138                 // we only draw the draw rect at the lowest nesting level
    139                 SkPaint paint;
    140                 paint.setColor(0xff000000 | fRandom.nextU());
    141                 canvas->drawRect(fDrawRect, paint);
    142             } else {
    143                 SkPoint childOffset = offset;
    144                 this->recurse(canvas, depth+1, childOffset);
    145 
    146                 childOffset += fSizes[depth+1];
    147                 this->recurse(canvas, depth+1, childOffset);
    148 
    149                 childOffset.fX = offset.fX + fSizes[depth+1].fX;
    150                 childOffset.fY = offset.fY;
    151                 this->recurse(canvas, depth+1, childOffset);
    152 
    153                 childOffset.fX = offset.fX;
    154                 childOffset.fY = offset.fY + fSizes[depth+1].fY;
    155                 this->recurse(canvas, depth+1, childOffset);
    156             }
    157 
    158             canvas->restore();
    159     }
    160 
    161     virtual void onDraw(int loops, SkCanvas* canvas) {
    162 
    163         for (int i = 0; i < loops; ++i) {
    164             SkPoint offset = SkPoint::Make(0, 0);
    165             this->recurse(canvas, 0, offset);
    166         }
    167     }
    168 
    169 private:
    170     typedef Benchmark INHERITED;
    171 };
    172 
    173 ////////////////////////////////////////////////////////////////////////////////
    174 class AAClipBuilderBench : public Benchmark {
    175     SkString fName;
    176     SkPath   fPath;
    177     SkRect   fRect;
    178     SkRegion fRegion;
    179     bool     fDoPath;
    180     bool     fDoAA;
    181 
    182 public:
    183     AAClipBuilderBench(bool doPath, bool doAA)  {
    184         fDoPath = doPath;
    185         fDoAA = doAA;
    186 
    187         fName.printf("aaclip_build_%s_%s", doPath ? "path" : "rect",
    188                      doAA ? "AA" : "BW");
    189 
    190         fRegion.setRect(0, 0, 640, 480);
    191         fRect.set(fRegion.getBounds());
    192         fRect.inset(SK_Scalar1/4, SK_Scalar1/4);
    193         fPath.addRoundRect(fRect, SkIntToScalar(20), SkIntToScalar(20));
    194     }
    195 
    196 protected:
    197     virtual const char* onGetName() { return fName.c_str(); }
    198     virtual void onDraw(int loops, SkCanvas*) {
    199         SkPaint paint;
    200         this->setupPaint(&paint);
    201 
    202         for (int i = 0; i < loops; ++i) {
    203             SkAAClip clip;
    204             if (fDoPath) {
    205                 clip.setPath(fPath, &fRegion, fDoAA);
    206             } else {
    207                 clip.setRect(fRect, fDoAA);
    208             }
    209         }
    210     }
    211 private:
    212     typedef Benchmark INHERITED;
    213 };
    214 
    215 ////////////////////////////////////////////////////////////////////////////////
    216 class AAClipRegionBench : public Benchmark {
    217 public:
    218     AAClipRegionBench()  {
    219         SkPath path;
    220         // test conversion of a complex clip to a aaclip
    221         path.addCircle(0, 0, SkIntToScalar(200));
    222         path.addCircle(0, 0, SkIntToScalar(180));
    223         // evenodd means we've constructed basically a stroked circle
    224         path.setFillType(SkPath::kEvenOdd_FillType);
    225 
    226         SkIRect bounds;
    227         path.getBounds().roundOut(&bounds);
    228         fRegion.setPath(path, SkRegion(bounds));
    229     }
    230 
    231 protected:
    232     virtual const char* onGetName() { return "aaclip_setregion"; }
    233     virtual void onDraw(int loops, SkCanvas*) {
    234         for (int i = 0; i < loops; ++i) {
    235             SkAAClip clip;
    236             clip.setRegion(fRegion);
    237         }
    238     }
    239 
    240 private:
    241     SkRegion fRegion;
    242     typedef Benchmark INHERITED;
    243 };
    244 
    245 ////////////////////////////////////////////////////////////////////////////////
    246 
    247 DEF_BENCH(return new AAClipBuilderBench(false, false);)
    248 DEF_BENCH(return new AAClipBuilderBench(false, true);)
    249 DEF_BENCH(return new AAClipBuilderBench(true, false);)
    250 DEF_BENCH(return new AAClipBuilderBench(true, true);)
    251 DEF_BENCH(return new AAClipRegionBench();)
    252 DEF_BENCH(return new AAClipBench(false, false);)
    253 DEF_BENCH(return new AAClipBench(false, true);)
    254 DEF_BENCH(return new AAClipBench(true, false);)
    255 DEF_BENCH(return new AAClipBench(true, true);)
    256 DEF_BENCH(return new NestedAAClipBench(false);)
    257 DEF_BENCH(return new NestedAAClipBench(true);)
    258