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