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(int loops,SkCanvas * canvas)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; 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 onDelayedSetup()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 onDraw(int loops,SkCanvas * canvas)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