2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
15 // This bench simulates the calls Skia sees from various HTML5 canvas
17 class GameBench : public Benchmark {
30 GameBench(Type type, Clear clear,
31 bool aligned = false, bool useAtlas = false,
32 bool useDrawVertices = false)
37 , fUseDrawVertices(useDrawVertices)
40 , fInitialized(false) {
44 fName.append("_scale");
47 fName.append("_trans");
55 fName.append("_aligned");
58 if (kPartial_Clear == clear) {
59 fName.append("_partial");
61 fName.append("_full");
65 fName.append("_atlas");
68 if (useDrawVertices) {
69 fName.append("_drawVerts");
72 // It's HTML 5 canvas, so always AA
77 const char* onGetName() override {
81 void onPreDraw() override {
83 this->makeCheckerboard();
89 void onDraw(const int loops, SkCanvas* canvas) override {
96 width = kAtlasCellWidth;
97 height = kAtlasCellHeight;
99 width = kCheckerboardWidth;
100 height = kCheckerboardHeight;
104 clearPaint.setColor(0xFF000000);
105 clearPaint.setAntiAlias(true);
107 SkISize size = canvas->getDeviceSize();
109 SkScalar maxTransX, maxTransY;
111 if (kScale_Type == fType) {
112 maxTransX = size.fWidth - (1.5f * width);
113 maxTransY = size.fHeight - (1.5f * height);
114 } else if (kTranslate_Type == fType) {
115 maxTransX = SkIntToScalar(size.fWidth - width);
116 maxTransY = SkIntToScalar(size.fHeight - height);
118 SkASSERT(kRotate_Type == fType);
119 // Yes, some rotations will be off the top and left sides
120 maxTransX = size.fWidth - SK_ScalarSqrt2 * height;
121 maxTransY = size.fHeight - SK_ScalarSqrt2 * height;
125 SkRect dst = { 0, 0, SkIntToScalar(width), SkIntToScalar(height) };
126 SkRect clearRect = { -1.0f, -1.0f, width+1.0f, height+1.0f };
127 SkPoint verts[4] = { // for drawVertices path
129 { 0, SkIntToScalar(height) },
130 { SkIntToScalar(width), SkIntToScalar(height) },
131 { SkIntToScalar(width), 0 }
133 uint16_t indices[6] = { 0, 1, 2, 0, 2, 3 };
136 p.setColor(0xFF000000);
137 p.setFilterQuality(kLow_SkFilterQuality);
139 SkPaint p2; // for drawVertices path
140 p2.setColor(0xFF000000);
141 p2.setFilterQuality(kLow_SkFilterQuality);
142 p2.setShader(SkShader::CreateBitmapShader(fAtlas,
143 SkShader::kClamp_TileMode,
144 SkShader::kClamp_TileMode))->unref();
146 for (int i = 0; i < loops; ++i, ++fNumSaved) {
147 if (0 == i % kNumBeforeClear) {
148 if (kPartial_Clear == fClear) {
149 for (int j = 0; j < fNumSaved; ++j) {
150 canvas->setMatrix(SkMatrix::I());
151 mat.setTranslate(fSaved[j][0], fSaved[j][1]);
153 if (kScale_Type == fType) {
154 mat.preScale(fSaved[j][2], fSaved[j][2]);
155 } else if (kRotate_Type == fType) {
156 mat.preRotate(fSaved[j][2]);
160 canvas->drawRect(clearRect, clearPaint);
163 canvas->clear(0xFF000000);
169 SkASSERT(fNumSaved < kNumBeforeClear);
171 canvas->setMatrix(SkMatrix::I());
173 fSaved[fNumSaved][0] = transRand.nextRangeScalar(0.0f, maxTransX);
174 fSaved[fNumSaved][1] = transRand.nextRangeScalar(0.0f, maxTransY);
176 // make the translations integer aligned
177 fSaved[fNumSaved][0] = SkScalarFloorToScalar(fSaved[fNumSaved][0]);
178 fSaved[fNumSaved][1] = SkScalarFloorToScalar(fSaved[fNumSaved][1]);
181 mat.setTranslate(fSaved[fNumSaved][0], fSaved[fNumSaved][1]);
183 if (kScale_Type == fType) {
184 fSaved[fNumSaved][2] = scaleRand.nextRangeScalar(0.5f, 1.5f);
185 mat.preScale(fSaved[fNumSaved][2], fSaved[fNumSaved][2]);
186 } else if (kRotate_Type == fType) {
187 fSaved[fNumSaved][2] = rotRand.nextRangeScalar(0.0f, 360.0f);
188 mat.preRotate(fSaved[fNumSaved][2]);
193 const int curCell = i % (kNumAtlasedX * kNumAtlasedY);
194 SkIRect src = fAtlasRects[curCell % (kNumAtlasedX)][curCell / (kNumAtlasedX)];
196 if (fUseDrawVertices) {
198 { SkIntToScalar(src.fLeft), SkIntToScalar(src.fBottom) },
199 { SkIntToScalar(src.fLeft), SkIntToScalar(src.fTop) },
200 { SkIntToScalar(src.fRight), SkIntToScalar(src.fTop) },
201 { SkIntToScalar(src.fRight), SkIntToScalar(src.fBottom) },
203 canvas->drawVertices(SkCanvas::kTriangles_VertexMode,
204 4, verts, uvs, NULL, NULL,
207 canvas->drawBitmapRect(fAtlas, &src, dst, &p,
208 SkCanvas::kBleed_DrawBitmapRectFlag);
211 canvas->drawBitmapRect(fCheckerboard, NULL, dst, &p);
217 static const int kCheckerboardWidth = 64;
218 static const int kCheckerboardHeight = 128;
220 static const int kAtlasCellWidth = 48;
221 static const int kAtlasCellHeight = 36;
222 static const int kNumAtlasedX = 5;
223 static const int kNumAtlasedY = 5;
224 static const int kAtlasSpacer = 2;
225 static const int kTotAtlasWidth = kNumAtlasedX * kAtlasCellWidth +
226 (kNumAtlasedX+1) * kAtlasSpacer;
227 static const int kTotAtlasHeight = kNumAtlasedY * kAtlasCellHeight +
228 (kNumAtlasedY+1) * kAtlasSpacer;
229 static const int kNumBeforeClear = 100;
235 bool fUseDrawVertices;
237 int fNumSaved; // num draws stored in 'fSaved'
240 // 0 & 1 are always x & y translate. 2 is either scale or rotate.
241 SkScalar fSaved[kNumBeforeClear][3];
243 SkBitmap fCheckerboard;
245 SkIRect fAtlasRects[kNumAtlasedX][kNumAtlasedY];
247 // Note: the resulting checker board has transparency
248 void makeCheckerboard() {
249 static int kCheckSize = 16;
251 fCheckerboard.allocN32Pixels(kCheckerboardWidth, kCheckerboardHeight);
252 SkAutoLockPixels lock(fCheckerboard);
253 for (int y = 0; y < kCheckerboardHeight; ++y) {
254 int even = (y / kCheckSize) % 2;
256 SkPMColor* scanline = fCheckerboard.getAddr32(0, y);
258 for (int x = 0; x < kCheckerboardWidth; ++x) {
259 if (even == (x / kCheckSize) % 2) {
260 *scanline++ = 0xFFFF0000;
262 *scanline++ = 0x00000000;
268 // Note: the resulting atlas has transparency
272 SkColor colors[kNumAtlasedX][kNumAtlasedY];
274 for (int y = 0; y < kNumAtlasedY; ++y) {
275 for (int x = 0; x < kNumAtlasedX; ++x) {
276 colors[x][y] = rand.nextU() | 0xff000000;
277 fAtlasRects[x][y] = SkIRect::MakeXYWH(kAtlasSpacer + x * (kAtlasCellWidth + kAtlasSpacer),
278 kAtlasSpacer + y * (kAtlasCellHeight + kAtlasSpacer),
284 fAtlas.allocN32Pixels(kTotAtlasWidth, kTotAtlasHeight);
285 SkAutoLockPixels lock(fAtlas);
287 for (int y = 0; y < kTotAtlasHeight; ++y) {
288 int colorY = y / (kAtlasCellHeight + kAtlasSpacer);
289 bool inColorY = (y % (kAtlasCellHeight + kAtlasSpacer)) >= kAtlasSpacer;
291 SkPMColor* scanline = fAtlas.getAddr32(0, y);
293 for (int x = 0; x < kTotAtlasWidth; ++x, ++scanline) {
294 int colorX = x / (kAtlasCellWidth + kAtlasSpacer);
295 bool inColorX = (x % (kAtlasCellWidth + kAtlasSpacer)) >= kAtlasSpacer;
297 if (inColorX && inColorY) {
298 SkASSERT(colorX < kNumAtlasedX && colorY < kNumAtlasedY);
299 *scanline = colors[colorX][colorY];
301 *scanline = 0x00000000;
307 typedef Benchmark INHERITED;
311 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kScale_Type,
312 GameBench::kPartial_Clear)); )
313 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type,
314 GameBench::kPartial_Clear)); )
315 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type,
316 GameBench::kPartial_Clear, true)); )
317 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kRotate_Type,
318 GameBench::kPartial_Clear)); )
321 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kScale_Type,
322 GameBench::kFull_Clear)); )
323 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type,
324 GameBench::kFull_Clear)); )
325 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type,
326 GameBench::kFull_Clear, true)); )
327 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kRotate_Type,
328 GameBench::kFull_Clear)); )
331 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type,
332 GameBench::kFull_Clear, false, true)); )
333 DEF_BENCH( return SkNEW_ARGS(GameBench, (GameBench::kTranslate_Type,
334 GameBench::kFull_Clear, false, true, true)); )