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 |