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 #include "Benchmark.h"
      8 #include "SkCanvas.h"
      9 #include "SkColor.h"
     10 #include "SkPaint.h"
     11 #include "SkPicture.h"
     12 #include "SkPictureRecorder.h"
     13 #include "SkPoint.h"
     14 #include "SkRandom.h"
     15 #include "SkRect.h"
     16 #include "SkString.h"
     17 
     18 // This is designed to emulate about 4 screens of textual content
     19 
     20 
     21 class PicturePlaybackBench : public Benchmark {
     22 public:
     23     PicturePlaybackBench(const char name[])  {
     24         fName.printf("picture_playback_%s", name);
     25         fPictureWidth = SkIntToScalar(PICTURE_WIDTH);
     26         fPictureHeight = SkIntToScalar(PICTURE_HEIGHT);
     27         fTextSize = SkIntToScalar(TEXT_SIZE);
     28     }
     29 
     30     enum {
     31         PICTURE_WIDTH = 1000,
     32         PICTURE_HEIGHT = 4000,
     33         TEXT_SIZE = 10
     34     };
     35 protected:
     36     virtual const char* onGetName() {
     37         return fName.c_str();
     38     }
     39 
     40     virtual void onDraw(int loops, SkCanvas* canvas) {
     41 
     42         SkPictureRecorder recorder;
     43         SkCanvas* pCanvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, nullptr, 0);
     44         this->recordCanvas(pCanvas);
     45         sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
     46 
     47         const SkPoint translateDelta = getTranslateDelta(loops);
     48 
     49         for (int i = 0; i < loops; i++) {
     50             picture->playback(canvas);
     51             canvas->translate(translateDelta.fX, translateDelta.fY);
     52         }
     53     }
     54 
     55     virtual void recordCanvas(SkCanvas* canvas) = 0;
     56     virtual SkPoint getTranslateDelta(int N) {
     57         SkIPoint canvasSize = onGetSize();
     58         return SkPoint::Make(SkIntToScalar((PICTURE_WIDTH - canvasSize.fX)/N),
     59                              SkIntToScalar((PICTURE_HEIGHT- canvasSize.fY)/N));
     60     }
     61 
     62     SkString fName;
     63     SkScalar fPictureWidth;
     64     SkScalar fPictureHeight;
     65     SkScalar fTextSize;
     66 private:
     67     typedef Benchmark INHERITED;
     68 };
     69 
     70 
     71 class TextPlaybackBench : public PicturePlaybackBench {
     72 public:
     73     TextPlaybackBench() : INHERITED("drawText") { }
     74 protected:
     75     void recordCanvas(SkCanvas* canvas) override {
     76         SkPaint paint;
     77         paint.setTextSize(fTextSize);
     78         paint.setColor(SK_ColorBLACK);
     79 
     80         const char* text = "Hamburgefons";
     81         size_t len = strlen(text);
     82         const SkScalar textWidth = paint.measureText(text, len);
     83 
     84         for (SkScalar x = 0; x < fPictureWidth; x += textWidth) {
     85             for (SkScalar y = 0; y < fPictureHeight; y += fTextSize) {
     86                 canvas->drawText(text, len, x, y, paint);
     87             }
     88         }
     89     }
     90 private:
     91     typedef PicturePlaybackBench INHERITED;
     92 };
     93 
     94 class PosTextPlaybackBench : public PicturePlaybackBench {
     95 public:
     96     PosTextPlaybackBench(bool drawPosH)
     97         : INHERITED(drawPosH ? "drawPosTextH" : "drawPosText")
     98         , fDrawPosH(drawPosH) { }
     99 protected:
    100     void recordCanvas(SkCanvas* canvas) override {
    101         SkPaint paint;
    102         paint.setTextSize(fTextSize);
    103         paint.setColor(SK_ColorBLACK);
    104 
    105         const char* text = "Hamburgefons";
    106         size_t len = strlen(text);
    107         const SkScalar textWidth = paint.measureText(text, len);
    108 
    109         SkScalar* adv = new SkScalar[len];
    110         paint.getTextWidths(text, len, adv);
    111 
    112         for (SkScalar x = 0; x < fPictureWidth; x += textWidth) {
    113             for (SkScalar y = 0; y < fPictureHeight; y += fTextSize) {
    114 
    115                 SkPoint* pos = new SkPoint[len];
    116                 SkScalar advX = 0;
    117 
    118                 for (size_t i = 0; i < len; i++) {
    119                     if (fDrawPosH)
    120                         pos[i].set(x + advX, y);
    121                     else
    122                         pos[i].set(x + advX, y + i);
    123                     advX += adv[i];
    124                 }
    125 
    126                 canvas->drawPosText(text, len, pos, paint);
    127                 delete[] pos;
    128             }
    129         }
    130         delete[] adv;
    131     }
    132 private:
    133     bool fDrawPosH;
    134     typedef PicturePlaybackBench INHERITED;
    135 };
    136 
    137 
    138 ///////////////////////////////////////////////////////////////////////////////
    139 
    140 DEF_BENCH( return new TextPlaybackBench(); )
    141 DEF_BENCH( return new PosTextPlaybackBench(true); )
    142 DEF_BENCH( return new PosTextPlaybackBench(false); )
    143 
    144 // Chrome draws into small tiles with impl-side painting.
    145 // This benchmark measures the relative performance of our bounding-box hierarchies,
    146 // both when querying tiles perfectly and when not.
    147 enum BBH  { kNone, kRTree };
    148 enum Mode { kTiled, kRandom };
    149 class TiledPlaybackBench : public Benchmark {
    150 public:
    151     TiledPlaybackBench(BBH bbh, Mode mode) : fBBH(bbh), fMode(mode), fName("tiled_playback") {
    152         switch (fBBH) {
    153             case kNone:     fName.append("_none"    ); break;
    154             case kRTree:    fName.append("_rtree"   ); break;
    155         }
    156         switch (fMode) {
    157             case kTiled:  fName.append("_tiled" ); break;
    158             case kRandom: fName.append("_random"); break;
    159         }
    160     }
    161 
    162     const char* onGetName() override { return fName.c_str(); }
    163     SkIPoint onGetSize() override { return SkIPoint::Make(1024,1024); }
    164 
    165     void onDelayedSetup() override {
    166         std::unique_ptr<SkBBHFactory> factory;
    167         switch (fBBH) {
    168             case kNone:                                                 break;
    169             case kRTree:    factory.reset(new SkRTreeFactory);          break;
    170         }
    171 
    172         SkPictureRecorder recorder;
    173         SkCanvas* canvas = recorder.beginRecording(1024, 1024, factory.get());
    174             SkRandom rand;
    175             for (int i = 0; i < 10000; i++) {
    176                 SkScalar x = rand.nextRangeScalar(0, 1024),
    177                          y = rand.nextRangeScalar(0, 1024),
    178                          w = rand.nextRangeScalar(0, 128),
    179                          h = rand.nextRangeScalar(0, 128);
    180                 SkPaint paint;
    181                 paint.setColor(rand.nextU());
    182                 paint.setAlpha(0xFF);
    183                 canvas->drawRect(SkRect::MakeXYWH(x,y,w,h), paint);
    184             }
    185         fPic = recorder.finishRecordingAsPicture();
    186     }
    187 
    188     void onDraw(int loops, SkCanvas* canvas) override {
    189         for (int i = 0; i < loops; i++) {
    190             // This inner loop guarantees we make the same choices for all bench variants.
    191             SkRandom rand;
    192             for (int j = 0; j < 10; j++) {
    193                 SkScalar x = 0, y = 0;
    194                 switch (fMode) {
    195                     case kTiled:  x = SkScalar(256 * rand.nextULessThan(4));
    196                                   y = SkScalar(256 * rand.nextULessThan(4));
    197                                   break;
    198                     case kRandom: x = rand.nextRangeScalar(0, 768);
    199                                   y = rand.nextRangeScalar(0, 768);
    200                                   break;
    201                 }
    202                 SkAutoCanvasRestore ar(canvas, true/*save now*/);
    203                 canvas->clipRect(SkRect::MakeXYWH(x,y,256,256));
    204                 fPic->playback(canvas);
    205             }
    206         }
    207     }
    208 
    209 private:
    210     BBH                 fBBH;
    211     Mode                fMode;
    212     SkString            fName;
    213     sk_sp<SkPicture>    fPic;
    214 };
    215 
    216 DEF_BENCH( return new TiledPlaybackBench(kNone,     kRandom); )
    217 DEF_BENCH( return new TiledPlaybackBench(kNone,     kTiled ); )
    218 DEF_BENCH( return new TiledPlaybackBench(kRTree,    kRandom); )
    219 DEF_BENCH( return new TiledPlaybackBench(kRTree,    kTiled ); )
    220