Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkBenchmark.h" | 8 #include "SkBenchmark.h" |
| 9 #include "SkCanvas.h" | 9 #include "SkCanvas.h" |
| 10 #include "SkPaint.h" | 10 #include "SkPaint.h" |
| 11 #include "SkRandom.h" | 11 #include "SkRandom.h" |
| 12 #include "SkString.h" | 12 #include "SkString.h" |
| 13 | 13 |
| 14 | |
| 15 // This bench simulates the calls Skia sees from various HTML5 canvas | 14 // This bench simulates the calls Skia sees from various HTML5 canvas |
| 16 // game bench marks | 15 // game bench marks |
| 17 class GameBench : public SkBenchmark { | 16 class GameBench : public SkBenchmark { |
| 18 public: | 17 public: |
| 19 enum Type { | 18 enum Type { |
| 20 kScale_Type, | 19 kScale_Type, |
| 21 kTranslate_Type, | 20 kTranslate_Type, |
| 22 kRotate_Type | 21 kRotate_Type |
| 23 }; | 22 }; |
| 24 | 23 |
| 25 GameBench(void* param, Type type, bool partialClear, bool aligned = false) | 24 enum Clear { |
| 25 kFull_Clear, | |
| 26 kPartial_Clear | |
| 27 }; | |
| 28 | |
| 29 GameBench(void* param, Type type, Clear clear, | |
| 30 bool aligned = false, bool useAtlas = false) | |
| 26 : INHERITED(param) | 31 : INHERITED(param) |
| 27 , fType(type) | 32 , fType(type) |
| 28 , fPartialClear(partialClear) | 33 , fClear(clear) |
| 29 , fAligned(aligned) | 34 , fAligned(aligned) |
| 35 , fUseAtlas(useAtlas) | |
| 30 , fName("game") | 36 , fName("game") |
| 31 , fNumSaved(0) | 37 , fNumSaved(0) |
| 32 , fInitialized(false) { | 38 , fInitialized(false) { |
| 33 | 39 |
| 34 switch (fType) { | 40 switch (fType) { |
| 35 case kScale_Type: | 41 case kScale_Type: |
| 36 fName.append("_scale"); | 42 fName.append("_scale"); |
| 37 break; | 43 break; |
| 38 case kTranslate_Type: | 44 case kTranslate_Type: |
| 39 fName.append("_trans"); | 45 fName.append("_trans"); |
| 40 break; | 46 break; |
| 41 case kRotate_Type: | 47 case kRotate_Type: |
| 42 fName.append("_rot"); | 48 fName.append("_rot"); |
| 43 break; | 49 break; |
| 44 }; | 50 }; |
| 45 | 51 |
| 46 if (aligned) { | 52 if (aligned) { |
| 47 fName.append("_aligned"); | 53 fName.append("_aligned"); |
| 48 } | 54 } |
| 49 | 55 |
| 50 if (partialClear) { | 56 if (kPartial_Clear == clear) { |
| 51 fName.append("_partial"); | 57 fName.append("_partial"); |
| 52 } else { | 58 } else { |
| 53 fName.append("_full"); | 59 fName.append("_full"); |
| 54 } | 60 } |
| 55 | 61 |
| 62 if (useAtlas) { | |
| 63 fName.append("_atlas"); | |
| 64 } | |
| 65 | |
| 56 // It's HTML 5 canvas, so always AA | 66 // It's HTML 5 canvas, so always AA |
| 57 fName.append("_aa"); | 67 fName.append("_aa"); |
| 58 } | 68 } |
| 59 | 69 |
| 60 protected: | 70 protected: |
| 61 virtual const char* onGetName() SK_OVERRIDE { | 71 virtual const char* onGetName() SK_OVERRIDE { |
| 62 return fName.c_str();; | 72 return fName.c_str(); |
| 63 } | 73 } |
| 64 | 74 |
| 65 virtual void onPreDraw() SK_OVERRIDE { | 75 virtual void onPreDraw() SK_OVERRIDE { |
| 66 if (!fInitialized) { | 76 if (!fInitialized) { |
| 67 this->makeCheckerboard(); | 77 this->makeCheckerboard(); |
| 78 this->makeAtlas(); | |
| 68 fInitialized = true; | 79 fInitialized = true; |
| 69 } | 80 } |
| 70 } | 81 } |
| 71 | 82 |
| 72 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { | 83 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { |
| 73 static SkMWCRandom scaleRand; | 84 static SkMWCRandom scaleRand; |
| 74 static SkMWCRandom transRand; | 85 static SkMWCRandom transRand; |
| 75 static SkMWCRandom rotRand; | 86 static SkMWCRandom rotRand; |
| 76 | 87 |
| 88 int width, height; | |
| 89 if (fUseAtlas) { | |
| 90 width = kAtlasCellWidth; | |
| 91 height = kAtlasCellHeight; | |
| 92 } else { | |
| 93 width = kCheckerboardWidth; | |
| 94 height = kCheckerboardHeight; | |
| 95 } | |
| 96 | |
| 77 SkPaint clearPaint; | 97 SkPaint clearPaint; |
| 78 clearPaint.setColor(0xFF000000); | 98 clearPaint.setColor(0xFF000000); |
| 79 clearPaint.setAntiAlias(true); | 99 clearPaint.setAntiAlias(true); |
| 80 | 100 |
| 81 SkISize size = canvas->getDeviceSize(); | 101 SkISize size = canvas->getDeviceSize(); |
| 82 | 102 |
| 83 SkScalar maxTransX, maxTransY; | 103 SkScalar maxTransX, maxTransY; |
| 84 | 104 |
| 85 if (kScale_Type == fType) { | 105 if (kScale_Type == fType) { |
| 86 maxTransX = size.fWidth - (1.5f * kCheckerboardWidth); | 106 maxTransX = size.fWidth - (1.5f * width); |
| 87 maxTransY = size.fHeight - (1.5f * kCheckerboardHeight); | 107 maxTransY = size.fHeight - (1.5f * height); |
| 88 } else if (kTranslate_Type == fType) { | 108 } else if (kTranslate_Type == fType) { |
| 89 maxTransX = SkIntToScalar(size.fWidth - kCheckerboardWidth); | 109 maxTransX = SkIntToScalar(size.fWidth - width); |
| 90 maxTransY = SkIntToScalar(size.fHeight - kCheckerboardHeight); | 110 maxTransY = SkIntToScalar(size.fHeight - height); |
| 91 } else { | 111 } else { |
| 92 SkASSERT(kRotate_Type == fType); | 112 SkASSERT(kRotate_Type == fType); |
| 93 // Yes, some rotations will be off the top and left sides | 113 // Yes, some rotations will be off the top and left sides |
| 94 maxTransX = size.fWidth - SK_ScalarSqrt2 * kCheckerboardHeight; | 114 maxTransX = size.fWidth - SK_ScalarSqrt2 * height; |
| 95 maxTransY = size.fHeight - SK_ScalarSqrt2 * kCheckerboardHeight; | 115 maxTransY = size.fHeight - SK_ScalarSqrt2 * height; |
| 96 } | 116 } |
| 97 | 117 |
| 98 SkMatrix mat; | 118 SkMatrix mat; |
| 99 SkIRect src = { 0, 0, kCheckerboardWidth, kCheckerboardHeight }; | 119 SkIRect src = { 0, 0, width, height }; |
| 100 SkRect dst = { 0, 0, kCheckerboardWidth, kCheckerboardHeight }; | 120 SkRect dst = { 0, 0, SkIntToScalar(width), SkIntToScalar(height) }; |
| 101 SkRect clearRect = { -1.0f, -1.0f, | 121 SkRect clearRect = { -1.0f, -1.0f, width+1.0f, height+1.0f }; |
| 102 kCheckerboardWidth+1.0f, kCheckerboardHeight+1.0f } ; | |
| 103 | 122 |
| 104 SkPaint p; | 123 SkPaint p; |
| 105 p.setColor(0xFF000000); | 124 p.setColor(0xFF000000); |
| 106 p.setFilterBitmap(true); | 125 p.setFilterBitmap(true); |
| 107 | 126 |
| 108 for (int i = 0; i < kNumRects; ++i, ++fNumSaved) { | 127 for (int i = 0; i < kNumRects; ++i, ++fNumSaved) { |
| 109 | 128 |
| 110 if (0 == i % kNumBeforeClear) { | 129 if (0 == i % kNumBeforeClear) { |
| 111 if (fPartialClear) { | 130 if (kPartial_Clear == fClear) { |
| 112 for (int j = 0; j < fNumSaved; ++j) { | 131 for (int j = 0; j < fNumSaved; ++j) { |
| 113 canvas->setMatrix(SkMatrix::I()); | 132 canvas->setMatrix(SkMatrix::I()); |
| 114 mat.setTranslate(fSaved[j][0], fSaved[j][1]); | 133 mat.setTranslate(fSaved[j][0], fSaved[j][1]); |
| 115 | 134 |
| 116 if (kScale_Type == fType) { | 135 if (kScale_Type == fType) { |
| 117 mat.preScale(fSaved[j][2], fSaved[j][2]); | 136 mat.preScale(fSaved[j][2], fSaved[j][2]); |
| 118 } else if (kRotate_Type == fType) { | 137 } else if (kRotate_Type == fType) { |
| 119 mat.preRotate(fSaved[j][2]); | 138 mat.preRotate(fSaved[j][2]); |
| 120 } | 139 } |
| 121 | 140 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 145 | 164 |
| 146 if (kScale_Type == fType) { | 165 if (kScale_Type == fType) { |
| 147 fSaved[fNumSaved][2] = scaleRand.nextRangeScalar(0.5f, 1.5f); | 166 fSaved[fNumSaved][2] = scaleRand.nextRangeScalar(0.5f, 1.5f); |
| 148 mat.preScale(fSaved[fNumSaved][2], fSaved[fNumSaved][2]); | 167 mat.preScale(fSaved[fNumSaved][2], fSaved[fNumSaved][2]); |
| 149 } else if (kRotate_Type == fType) { | 168 } else if (kRotate_Type == fType) { |
| 150 fSaved[fNumSaved][2] = rotRand.nextRangeScalar(0.0f, 360.0f); | 169 fSaved[fNumSaved][2] = rotRand.nextRangeScalar(0.0f, 360.0f); |
| 151 mat.preRotate(fSaved[fNumSaved][2]); | 170 mat.preRotate(fSaved[fNumSaved][2]); |
| 152 } | 171 } |
| 153 | 172 |
| 154 canvas->concat(mat); | 173 canvas->concat(mat); |
| 155 canvas->drawBitmapRect(fCheckerboard, &src, dst, &p); | 174 if (fUseAtlas) { |
| 175 static int curCell = 0; | |
| 176 src = fAtlasRects[curCell % (kNumAtlasedX)][curCell / (kNumAtlas edX)]; | |
| 177 curCell = (curCell + 1) % (kNumAtlasedX*kNumAtlasedY); | |
| 178 canvas->drawBitmapRect(fAtlas, &src, dst, &p); | |
| 179 } else { | |
| 180 canvas->drawBitmapRect(fCheckerboard, &src, dst, &p); | |
| 181 } | |
| 156 } | 182 } |
| 157 } | 183 } |
| 158 | 184 |
| 159 private: | 185 private: |
| 160 static const int kCheckerboardWidth = 64; | 186 static const int kCheckerboardWidth = 64; |
| 161 static const int kCheckerboardHeight = 128; | 187 static const int kCheckerboardHeight = 128; |
| 188 | |
| 189 static const int kAtlasCellWidth = 48; | |
| 190 static const int kAtlasCellHeight = 36; | |
| 191 static const int kNumAtlasedX = 5; | |
| 192 static const int kNumAtlasedY = 5; | |
| 193 static const int kAtlasSpacer = 2; | |
| 194 static const int kTotAtlasWidth = kNumAtlasedX * kAtlasCellWidth + | |
| 195 (kNumAtlasedX+1) * kAtlasSpacer; | |
| 196 static const int kTotAtlasHeight = kNumAtlasedY * kAtlasCellHeight + | |
| 197 (kNumAtlasedY+1) * kAtlasSpacer; | |
| 198 | |
| 162 #ifdef SK_DEBUG | 199 #ifdef SK_DEBUG |
| 163 static const int kNumRects = 100; | 200 static const int kNumRects = 100; |
| 164 static const int kNumBeforeClear = 10; | 201 static const int kNumBeforeClear = 10; |
| 165 #else | 202 #else |
| 166 static const int kNumRects = 5000; | 203 static const int kNumRects = 5000; |
| 167 static const int kNumBeforeClear = 300; | 204 static const int kNumBeforeClear = 300; |
| 168 #endif | 205 #endif |
| 169 | 206 |
| 170 | 207 |
| 171 Type fType; | 208 Type fType; |
| 172 bool fPartialClear; | 209 Clear fClear; |
| 173 bool fAligned; | 210 bool fAligned; |
| 211 bool fUseAtlas; | |
| 174 SkString fName; | 212 SkString fName; |
| 175 int fNumSaved; // num draws stored in 'fSaved' | 213 int fNumSaved; // num draws stored in 'fSaved' |
| 176 bool fInitialized; | 214 bool fInitialized; |
| 177 | 215 |
| 178 // 0 & 1 are always x & y translate. 2 is either scale or rotate. | 216 // 0 & 1 are always x & y translate. 2 is either scale or rotate. |
| 179 SkScalar fSaved[kNumBeforeClear][3]; | 217 SkScalar fSaved[kNumBeforeClear][3]; |
| 218 | |
| 180 SkBitmap fCheckerboard; | 219 SkBitmap fCheckerboard; |
| 220 SkBitmap fAtlas; | |
| 221 SkIRect fAtlasRects[kNumAtlasedX][kNumAtlasedY]; | |
| 181 | 222 |
| 182 // Note: the resulting checker board has transparency | 223 // Note: the resulting checker board has transparency |
| 183 void makeCheckerboard() { | 224 void makeCheckerboard() { |
| 184 static int kCheckSize = 16; | 225 static int kCheckSize = 16; |
| 185 | 226 |
| 186 fCheckerboard.setConfig(SkBitmap::kARGB_8888_Config, | 227 fCheckerboard.setConfig(SkBitmap::kARGB_8888_Config, |
| 187 kCheckerboardWidth, kCheckerboardHeight); | 228 kCheckerboardWidth, kCheckerboardHeight); |
| 188 fCheckerboard.allocPixels(); | 229 fCheckerboard.allocPixels(); |
| 189 SkAutoLockPixels lock(fCheckerboard); | 230 SkAutoLockPixels lock(fCheckerboard); |
| 190 for (int y = 0; y < kCheckerboardHeight; ++y) { | 231 for (int y = 0; y < kCheckerboardHeight; ++y) { |
| 191 int even = (y / kCheckSize) % 2; | 232 int even = (y / kCheckSize) % 2; |
| 192 | 233 |
| 193 SkPMColor* scanline = fCheckerboard.getAddr32(0, y); | 234 SkPMColor* scanline = fCheckerboard.getAddr32(0, y); |
| 194 | 235 |
| 195 for (int x = 0; x < kCheckerboardWidth; ++x) { | 236 for (int x = 0; x < kCheckerboardWidth; ++x) { |
| 196 if (even == (x / kCheckSize) % 2) { | 237 if (even == (x / kCheckSize) % 2) { |
| 197 *scanline++ = 0xFFFF0000; | 238 *scanline++ = 0xFFFF0000; |
| 198 } else { | 239 } else { |
| 199 *scanline++ = 0x00000000; | 240 *scanline++ = 0x00000000; |
| 200 } | 241 } |
| 201 } | 242 } |
| 202 } | 243 } |
| 203 } | 244 } |
| 204 | 245 |
| 246 // Note: the resulting atlas has transparency | |
| 247 void makeAtlas() { | |
| 248 SkMWCRandom rand; | |
| 249 | |
| 250 SkColor colors[kNumAtlasedX][kNumAtlasedY]; | |
| 251 | |
| 252 for (int y = 0; y < kNumAtlasedY; ++y) { | |
| 253 for (int x = 0; x < kNumAtlasedX; ++x) { | |
| 254 colors[x][y] = rand.nextU() | 0xff000000; | |
| 255 fAtlasRects[x][y] = SkIRect::MakeXYWH(kAtlasSpacer + x * (kAtlas CellWidth + kAtlasSpacer), | |
|
bsalomon
2013/05/30 18:32:17
long lines (if you care).
| |
| 256 kAtlasSpacer + y * (kAtlas CellHeight + kAtlasSpacer), | |
| 257 kAtlasCellWidth, | |
| 258 kAtlasCellHeight); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 | |
| 263 fAtlas.setConfig(SkBitmap::kARGB_8888_Config, kTotAtlasWidth, kTotAtlasH eight); | |
| 264 fAtlas.allocPixels(); | |
| 265 SkAutoLockPixels lock(fAtlas); | |
| 266 | |
| 267 for (int y = 0; y < kTotAtlasHeight; ++y) { | |
| 268 int colorY = y / (kAtlasCellHeight + kAtlasSpacer); | |
| 269 bool inColorY = (y % (kAtlasCellHeight + kAtlasSpacer)) >= kAtlasSpa cer; | |
| 270 | |
| 271 SkPMColor* scanline = fAtlas.getAddr32(0, y); | |
| 272 | |
| 273 for (int x = 0; x < kTotAtlasWidth; ++x, ++scanline) { | |
| 274 int colorX = x / (kAtlasCellWidth + kAtlasSpacer); | |
| 275 bool inColorX = (x % (kAtlasCellWidth + kAtlasSpacer)) >= kAtlas Spacer; | |
| 276 | |
| 277 if (inColorX && inColorY) { | |
| 278 SkASSERT(colorX < kNumAtlasedX && colorY < kNumAtlasedY); | |
| 279 *scanline = colors[colorX][colorY]; | |
| 280 } else { | |
| 281 *scanline = 0x00000000; | |
| 282 } | |
| 283 } | |
| 284 } | |
| 285 } | |
| 286 | |
| 205 typedef SkBenchmark INHERITED; | 287 typedef SkBenchmark INHERITED; |
| 206 }; | 288 }; |
| 207 | 289 |
| 208 // Partial clear | 290 // Partial clear |
| 209 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, false)); ) | 291 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, |
| 210 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, false)); ) | 292 GameBench::kPartial_Clear)); ) |
| 211 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, false, t rue)); ) | 293 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, |
| 212 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, false)); ) | 294 GameBench::kPartial_Clear)); ) |
| 295 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, | |
| 296 GameBench::kPartial_Clear, true)); ) | |
| 297 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, | |
| 298 GameBench::kPartial_Clear)); ) | |
| 213 | 299 |
| 214 // Full clear | 300 // Full clear |
| 215 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, true)); ) | 301 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, |
| 216 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, true)); ) | 302 GameBench::kFull_Clear)); ) |
| 217 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, true, tr ue)); ) | 303 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, |
| 218 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, true)); ) | 304 GameBench::kFull_Clear)); ) |
| 305 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, | |
| 306 GameBench::kFull_Clear, true)); ) | |
| 307 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, | |
| 308 GameBench::kFull_Clear)); ) | |
| 309 | |
| 310 // Atlased | |
| 311 DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, | |
| 312 GameBench::kFull_Clear, false, true) ); ) | |
| OLD | NEW |