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:
PicturePlaybackBench(const char name[])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:
onGetName()36     virtual const char* onGetName() {
37         return fName.c_str();
38     }
39 
onDraw(const int loops,SkCanvas * canvas)40     virtual void onDraw(const int loops, SkCanvas* canvas) {
41 
42         SkPictureRecorder recorder;
43         SkCanvas* pCanvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0);
44         this->recordCanvas(pCanvas);
45         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
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;
getTranslateDelta(int N)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:
TextPlaybackBench()73     TextPlaybackBench() : INHERITED("drawText") { }
74 protected:
recordCanvas(SkCanvas * canvas)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:
PosTextPlaybackBench(bool drawPosH)96     PosTextPlaybackBench(bool drawPosH)
97         : INHERITED(drawPosH ? "drawPosTextH" : "drawPosText")
98         , fDrawPosH(drawPosH) { }
99 protected:
recordCanvas(SkCanvas * canvas)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:
TiledPlaybackBench(BBH bbh,Mode mode)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 
onGetName()162     const char* onGetName() override { return fName.c_str(); }
onGetSize()163     SkIPoint onGetSize() override { return SkIPoint::Make(1024,1024); }
164 
onPreDraw()165     void onPreDraw() override {
166         SkAutoTDelete<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);
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.reset(recorder.endRecording());
186     }
187 
onDraw(const int loops,SkCanvas * canvas)188     void onDraw(const 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     SkAutoTUnref<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