Home | History | Annotate | Download | only in bench
      1 /*
      2  * Copyright 2012 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 #include "SkBenchmark.h"
      8 #include "SkCanvas.h"
      9 #include "SkColor.h"
     10 #include "SkPaint.h"
     11 #include "SkPicture.h"
     12 #include "SkPoint.h"
     13 #include "SkRandom.h"
     14 #include "SkRect.h"
     15 #include "SkString.h"
     16 
     17 class PictureRecordBench : public SkBenchmark {
     18 public:
     19     PictureRecordBench(void* param, const char name[]) : INHERITED(param) {
     20         fName.printf("picture_record_%s", name);
     21         fPictureWidth = SkIntToScalar(PICTURE_WIDTH);
     22         fPictureHeight = SkIntToScalar(PICTURE_HEIGHT);
     23         fIsRendering = false;
     24     }
     25 
     26     enum {
     27         N = SkBENCHLOOP(25), // number of times to create the picture
     28         PICTURE_WIDTH = 1000,
     29         PICTURE_HEIGHT = 4000,
     30     };
     31 protected:
     32     virtual const char* onGetName() {
     33         return fName.c_str();
     34     }
     35 
     36     virtual void onDraw(SkCanvas*) {
     37         int n = (int)(N * this->innerLoopScale());
     38         n = SkMax32(1, n);
     39 
     40         for (int i = 0; i < n; i++) {
     41 
     42             SkPicture picture;
     43 
     44             SkCanvas* pCanvas = picture.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT);
     45             recordCanvas(pCanvas);
     46 
     47             // we don't need to draw the picture as the endRecording step will
     48             // do the work of transferring the recorded content into a playback
     49             // object.
     50             picture.endRecording();
     51         }
     52     }
     53 
     54     virtual void recordCanvas(SkCanvas* canvas) = 0;
     55     virtual float innerLoopScale() const { return 1; }
     56 
     57     SkString fName;
     58     SkScalar fPictureWidth;
     59     SkScalar fPictureHeight;
     60     SkScalar fTextSize;
     61 private:
     62     typedef SkBenchmark INHERITED;
     63 };
     64 
     65 /*
     66  *  An SkPicture has internal dictionaries to store bitmaps, matrices, paints,
     67  *  and regions.  This bench populates those dictionaries to test the speed of
     68  *  reading and writing to those particular dictionary data structures.
     69  */
     70 class DictionaryRecordBench : public PictureRecordBench {
     71 public:
     72     DictionaryRecordBench(void* param)
     73         : INHERITED(param, "dictionaries") { }
     74 
     75     enum {
     76         M = SkBENCHLOOP(100),   // number of elements in each dictionary
     77     };
     78 protected:
     79     virtual void recordCanvas(SkCanvas* canvas) {
     80 
     81         const SkPoint translateDelta = getTranslateDelta();
     82 
     83         for (int i = 0; i < M; i++) {
     84 
     85             SkColor color = SK_ColorYELLOW + (i % 255);
     86             SkIRect rect = SkIRect::MakeWH(i,i);
     87 
     88             canvas->save();
     89 
     90             // set the clip to the given region
     91             SkRegion region;
     92             region.setRect(rect);
     93             canvas->clipRegion(region);
     94 
     95             // fill the clip with a color
     96             SkPaint paint;
     97             paint.setColor(color);
     98             canvas->drawPaint(paint);
     99 
    100             // set a matrix on the canvas
    101             SkMatrix matrix;
    102             matrix.setRotate(SkIntToScalar(i % 360));
    103             canvas->setMatrix(matrix);
    104 
    105             // create a simple bitmap
    106             SkBitmap bitmap;
    107             bitmap.setConfig(SkBitmap::kRGB_565_Config, 10, 10);
    108             bitmap.allocPixels();
    109 
    110             // draw a single color into the bitmap
    111             SkCanvas bitmapCanvas(bitmap);
    112             bitmapCanvas.drawColor(SkColorSetA(color, i % 255));
    113 
    114             // draw the bitmap onto the canvas
    115             canvas->drawBitmapMatrix(bitmap, matrix);
    116 
    117             canvas->restore();
    118             canvas->translate(translateDelta.fX, translateDelta.fY);
    119         }
    120     }
    121 
    122     SkPoint getTranslateDelta() {
    123         SkIPoint canvasSize = onGetSize();
    124         return SkPoint::Make(SkIntToScalar((PICTURE_WIDTH - canvasSize.fX)/M),
    125                              SkIntToScalar((PICTURE_HEIGHT- canvasSize.fY)/M));
    126     }
    127 private:
    128     typedef PictureRecordBench INHERITED;
    129 };
    130 
    131 /*
    132  *  Populates the SkPaint dictionary with a large number of unique paint
    133  *  objects that differ only by color
    134  */
    135 class UniquePaintDictionaryRecordBench : public PictureRecordBench {
    136 public:
    137     UniquePaintDictionaryRecordBench(void* param)
    138         : INHERITED(param, "unique_paint_dictionary") { }
    139 
    140     enum {
    141         M = SkBENCHLOOP(15000),   // number of unique paint objects
    142     };
    143 protected:
    144     virtual float innerLoopScale() const SK_OVERRIDE { return 0.1f; }
    145     virtual void recordCanvas(SkCanvas* canvas) {
    146         SkRandom rand;
    147         for (int i = 0; i < M; i++) {
    148             SkPaint paint;
    149             paint.setColor(rand.nextU());
    150             canvas->drawPaint(paint);
    151         }
    152     }
    153 
    154 private:
    155     typedef PictureRecordBench INHERITED;
    156 };
    157 
    158 /*
    159  *  Populates the SkPaint dictionary with a number of unique paint
    160  *  objects that get reused repeatedly.
    161  *
    162  *  Re-creating the paint objects in the inner loop slows the benchmark down 10%.
    163  *  Using setColor(i % objCount) instead of a random color creates a very high rate
    164  *  of hash conflicts, slowing us down 12%.
    165  */
    166 class RecurringPaintDictionaryRecordBench : public PictureRecordBench {
    167 public:
    168     RecurringPaintDictionaryRecordBench(void* param)
    169         : INHERITED(param, "recurring_paint_dictionary") {
    170         SkRandom rand;
    171         for (int i = 0; i < ObjCount; i++) {
    172             fPaint[i].setColor(rand.nextU());
    173         }
    174     }
    175 
    176     enum {
    177         ObjCount = 100,           // number of unique paint objects
    178         M = SkBENCHLOOP(50000),   // number of draw iterations
    179     };
    180 protected:
    181     virtual float innerLoopScale() const SK_OVERRIDE { return 0.1f; }
    182     virtual void recordCanvas(SkCanvas* canvas) {
    183 
    184         for (int i = 0; i < M; i++) {
    185             canvas->drawPaint(fPaint[i % ObjCount]);
    186         }
    187     }
    188 
    189 private:
    190     SkPaint fPaint [ObjCount];
    191     typedef PictureRecordBench INHERITED;
    192 };
    193 
    194 ///////////////////////////////////////////////////////////////////////////////
    195 
    196 static SkBenchmark* Fact0(void* p) { return new DictionaryRecordBench(p); }
    197 static SkBenchmark* Fact1(void* p) { return new UniquePaintDictionaryRecordBench(p); }
    198 static SkBenchmark* Fact2(void* p) { return new RecurringPaintDictionaryRecordBench(p); }
    199 
    200 static BenchRegistry gReg0(Fact0);
    201 static BenchRegistry gReg1(Fact1);
    202 static BenchRegistry gReg2(Fact2);
    203