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 "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 class PictureRecordBench : public Benchmark { 19 public: 20 PictureRecordBench(const char name[]) { 21 fName.printf("picture_record_%s", name); 22 } 23 24 virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { 25 return backend == kNonRendering_Backend; 26 } 27 28 enum { 29 PICTURE_WIDTH = 1000, 30 PICTURE_HEIGHT = 4000, 31 }; 32 protected: 33 virtual const char* onGetName() SK_OVERRIDE { 34 return fName.c_str(); 35 } 36 private: 37 SkString fName; 38 typedef Benchmark INHERITED; 39 }; 40 41 42 static const int kMaxLoopsPerCanvas = 10000; 43 44 /* 45 * An SkPicture has internal dictionaries to store bitmaps, matrices, paints, 46 * and regions. This bench populates those dictionaries to test the speed of 47 * reading and writing to those particular dictionary data structures. 48 */ 49 class DictionaryRecordBench : public PictureRecordBench { 50 public: 51 DictionaryRecordBench() : INHERITED("dictionaries") {} 52 53 protected: 54 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 55 SkPictureRecorder recorder; 56 SkCanvas* canvas = NULL; 57 58 const SkPoint translateDelta = getTranslateDelta(loops); 59 60 for (int i = 0; i < loops; i++) { 61 if (0 == i % kMaxLoopsPerCanvas) { 62 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 63 canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); 64 } 65 66 SkColor color = SK_ColorYELLOW + (i % 255); 67 SkIRect rect = SkIRect::MakeWH(i % PICTURE_WIDTH, i % PICTURE_HEIGHT); 68 69 canvas->save(); 70 71 // set the clip to the given region 72 SkRegion region; 73 region.setRect(rect); 74 canvas->clipRegion(region); 75 76 // fill the clip with a color 77 SkPaint paint; 78 paint.setColor(color); 79 canvas->drawPaint(paint); 80 81 // set a matrix on the canvas 82 SkMatrix matrix; 83 matrix.setRotate(SkIntToScalar(i % 360)); 84 canvas->setMatrix(matrix); 85 86 // create a simple bitmap 87 SkBitmap bitmap; 88 bitmap.allocPixels(SkImageInfo::Make(10, 10, 89 kRGB_565_SkColorType, kOpaque_SkAlphaType)); 90 91 // draw a single color into the bitmap 92 SkCanvas bitmapCanvas(bitmap); 93 bitmapCanvas.drawColor(SkColorSetA(color, i % 255)); 94 95 // draw the bitmap onto the canvas 96 canvas->drawBitmapMatrix(bitmap, matrix); 97 98 canvas->restore(); 99 canvas->translate(translateDelta.fX, translateDelta.fY); 100 } 101 } 102 103 SkPoint getTranslateDelta(int M) { 104 SkIPoint canvasSize = onGetSize(); 105 return SkPoint::Make(SkIntToScalar((PICTURE_WIDTH - canvasSize.fX)/M), 106 SkIntToScalar((PICTURE_HEIGHT- canvasSize.fY)/M)); 107 } 108 private: 109 typedef PictureRecordBench INHERITED; 110 }; 111 112 /* 113 * Populates the SkPaint dictionary with a large number of unique paint 114 * objects that differ only by color 115 */ 116 class UniquePaintDictionaryRecordBench : public PictureRecordBench { 117 public: 118 UniquePaintDictionaryRecordBench() : INHERITED("unique_paint_dictionary") { } 119 120 protected: 121 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 122 SkRandom rand; 123 SkPaint paint; 124 SkPictureRecorder recorder; 125 SkCanvas* canvas = NULL; 126 for (int i = 0; i < loops; i++) { 127 if (0 == i % kMaxLoopsPerCanvas) { 128 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 129 canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); 130 } 131 paint.setColor(rand.nextU()); 132 canvas->drawPaint(paint); 133 } 134 } 135 136 private: 137 typedef PictureRecordBench INHERITED; 138 }; 139 140 /* 141 * Populates the SkPaint dictionary with a number of unique paint 142 * objects that get reused repeatedly. 143 * 144 * Re-creating the paint objects in the inner loop slows the benchmark down 10%. 145 * Using setColor(i % objCount) instead of a random color creates a very high rate 146 * of hash conflicts, slowing us down 12%. 147 */ 148 class RecurringPaintDictionaryRecordBench : public PictureRecordBench { 149 public: 150 RecurringPaintDictionaryRecordBench() : INHERITED("recurring_paint_dictionary") { 151 SkRandom rand; 152 for (int i = 0; i < ObjCount; i++) { 153 fPaint[i].setColor(rand.nextU()); 154 } 155 } 156 157 enum { 158 ObjCount = 100, // number of unique paint objects 159 }; 160 protected: 161 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 162 SkPictureRecorder recorder; 163 SkCanvas* canvas = recorder.beginRecording(PICTURE_WIDTH, PICTURE_HEIGHT, NULL, 0); 164 for (int i = 0; i < loops; i++) { 165 canvas->drawPaint(fPaint[i % ObjCount]); 166 } 167 } 168 169 private: 170 SkPaint fPaint [ObjCount]; 171 typedef PictureRecordBench INHERITED; 172 }; 173 174 /////////////////////////////////////////////////////////////////////////////// 175 176 DEF_BENCH( return new DictionaryRecordBench(); ) 177 DEF_BENCH( return new UniquePaintDictionaryRecordBench(); ) 178 DEF_BENCH( return new RecurringPaintDictionaryRecordBench(); ) 179