blob: 4998bd84148a1ea10e55fcd25bcbe2772a47b2cb [file] [log] [blame]
robertphillips@google.com6670ab92013-05-09 19:03:48 +00001/*
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
8#include "SkBenchmark.h"
9#include "SkCanvas.h"
10#include "SkPaint.h"
11#include "SkRandom.h"
12#include "SkString.h"
13
14
15// This bench simulates the calls Skia sees from various HTML5 canvas
16// game bench marks
17class GameBench : public SkBenchmark {
18public:
19 enum Type {
skia.committer@gmail.com0f20a3f2013-05-10 07:01:04 +000020 kScale_Type,
21 kTranslate_Type,
robertphillips@google.com6670ab92013-05-09 19:03:48 +000022 kRotate_Type
23 };
24
robertphillips@google.com347fd4e2013-05-15 14:18:32 +000025 GameBench(void* param, Type type, bool partialClear, bool aligned = false)
robertphillips@google.com6670ab92013-05-09 19:03:48 +000026 : INHERITED(param)
27 , fType(type)
28 , fPartialClear(partialClear)
robertphillips@google.com347fd4e2013-05-15 14:18:32 +000029 , fAligned(aligned)
robertphillips@google.com6670ab92013-05-09 19:03:48 +000030 , fName("game")
31 , fNumSaved(0)
32 , fInitialized(false) {
33
34 switch (fType) {
35 case kScale_Type:
36 fName.append("_scale");
37 break;
38 case kTranslate_Type:
39 fName.append("_trans");
40 break;
41 case kRotate_Type:
42 fName.append("_rot");
43 break;
44 };
45
robertphillips@google.com347fd4e2013-05-15 14:18:32 +000046 if (aligned) {
47 fName.append("_aligned");
48 }
49
robertphillips@google.com6670ab92013-05-09 19:03:48 +000050 if (partialClear) {
51 fName.append("_partial");
52 } else {
53 fName.append("_full");
54 }
55
56 // It's HTML 5 canvas, so always AA
57 fName.append("_aa");
58 }
59
60protected:
61 virtual const char* onGetName() SK_OVERRIDE {
62 return fName.c_str();;
63 }
64
65 virtual void onPreDraw() SK_OVERRIDE {
66 if (!fInitialized) {
67 this->makeCheckerboard();
68 fInitialized = true;
69 }
70 }
71
72 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
73 static SkMWCRandom scaleRand;
74 static SkMWCRandom transRand;
75 static SkMWCRandom rotRand;
76
77 SkPaint clearPaint;
78 clearPaint.setColor(0xFF000000);
79 clearPaint.setAntiAlias(true);
80
81 SkISize size = canvas->getDeviceSize();
82
83 SkScalar maxTransX, maxTransY;
84
85 if (kScale_Type == fType) {
86 maxTransX = size.fWidth - (1.5f * kCheckerboardWidth);
87 maxTransY = size.fHeight - (1.5f * kCheckerboardHeight);
88 } else if (kTranslate_Type == fType) {
89 maxTransX = SkIntToScalar(size.fWidth - kCheckerboardWidth);
90 maxTransY = SkIntToScalar(size.fHeight - kCheckerboardHeight);
91 } else {
92 SkASSERT(kRotate_Type == fType);
93 // Yes, some rotations will be off the top and left sides
94 maxTransX = size.fWidth - SK_ScalarSqrt2 * kCheckerboardHeight;
95 maxTransY = size.fHeight - SK_ScalarSqrt2 * kCheckerboardHeight;
96 }
97
98 SkMatrix mat;
99 SkIRect src = { 0, 0, kCheckerboardWidth, kCheckerboardHeight };
100 SkRect dst = { 0, 0, kCheckerboardWidth, kCheckerboardHeight };
skia.committer@gmail.com0f20a3f2013-05-10 07:01:04 +0000101 SkRect clearRect = { -1.0f, -1.0f,
robertphillips@google.com6670ab92013-05-09 19:03:48 +0000102 kCheckerboardWidth+1.0f, kCheckerboardHeight+1.0f };
103
104 SkPaint p;
105 p.setColor(0xFF000000);
106 p.setFilterBitmap(true);
107
108 for (int i = 0; i < kNumRects; ++i, ++fNumSaved) {
109
110 if (0 == i % kNumBeforeClear) {
111 if (fPartialClear) {
112 for (int j = 0; j < fNumSaved; ++j) {
113 canvas->setMatrix(SkMatrix::I());
114 mat.setTranslate(fSaved[j][0], fSaved[j][1]);
115
116 if (kScale_Type == fType) {
117 mat.preScale(fSaved[j][2], fSaved[j][2]);
118 } else if (kRotate_Type == fType) {
119 mat.preRotate(fSaved[j][2]);
120 }
121
122 canvas->concat(mat);
123 canvas->drawRect(clearRect, clearPaint);
124 }
125 } else {
126 canvas->clear(0xFF000000);
127 }
128
129 fNumSaved = 0;
130 }
131
132 SkASSERT(fNumSaved < kNumBeforeClear);
133
134 canvas->setMatrix(SkMatrix::I());
135
136 fSaved[fNumSaved][0] = transRand.nextRangeScalar(0.0f, maxTransX);
137 fSaved[fNumSaved][1] = transRand.nextRangeScalar(0.0f, maxTransY);
robertphillips@google.com347fd4e2013-05-15 14:18:32 +0000138 if (fAligned) {
139 // make the translations integer aligned
140 fSaved[fNumSaved][0] = SkScalarFloorToScalar(fSaved[fNumSaved][0]);
141 fSaved[fNumSaved][1] = SkScalarFloorToScalar(fSaved[fNumSaved][1]);
142 }
robertphillips@google.com6670ab92013-05-09 19:03:48 +0000143
144 mat.setTranslate(fSaved[fNumSaved][0], fSaved[fNumSaved][1]);
145
146 if (kScale_Type == fType) {
147 fSaved[fNumSaved][2] = scaleRand.nextRangeScalar(0.5f, 1.5f);
148 mat.preScale(fSaved[fNumSaved][2], fSaved[fNumSaved][2]);
149 } else if (kRotate_Type == fType) {
150 fSaved[fNumSaved][2] = rotRand.nextRangeScalar(0.0f, 360.0f);
151 mat.preRotate(fSaved[fNumSaved][2]);
152 }
153
154 canvas->concat(mat);
155 canvas->drawBitmapRect(fCheckerboard, &src, dst, &p);
156 }
157 }
158
159private:
160 static const int kCheckerboardWidth = 64;
161 static const int kCheckerboardHeight = 128;
162#ifdef SK_DEBUG
163 static const int kNumRects = 100;
164 static const int kNumBeforeClear = 10;
165#else
166 static const int kNumRects = 5000;
167 static const int kNumBeforeClear = 300;
168#endif
169
170
171 Type fType;
172 bool fPartialClear;
robertphillips@google.com347fd4e2013-05-15 14:18:32 +0000173 bool fAligned;
robertphillips@google.com6670ab92013-05-09 19:03:48 +0000174 SkString fName;
175 int fNumSaved; // num draws stored in 'fSaved'
176 bool fInitialized;
177
178 // 0 & 1 are always x & y translate. 2 is either scale or rotate.
179 SkScalar fSaved[kNumBeforeClear][3];
180 SkBitmap fCheckerboard;
181
182 // Note: the resulting checker board has transparency
183 void makeCheckerboard() {
robertphillips@google.com6d58ad32013-05-09 19:08:57 +0000184 static int kCheckSize = 16;
robertphillips@google.com6670ab92013-05-09 19:03:48 +0000185
186 fCheckerboard.setConfig(SkBitmap::kARGB_8888_Config,
187 kCheckerboardWidth, kCheckerboardHeight);
188 fCheckerboard.allocPixels();
189 SkAutoLockPixels lock(fCheckerboard);
robertphillips@google.com6d58ad32013-05-09 19:08:57 +0000190 for (int y = 0; y < kCheckerboardHeight; ++y) {
robertphillips@google.com6670ab92013-05-09 19:03:48 +0000191 int even = (y / kCheckSize) % 2;
192
193 SkPMColor* scanline = fCheckerboard.getAddr32(0, y);
194
robertphillips@google.com6d58ad32013-05-09 19:08:57 +0000195 for (int x = 0; x < kCheckerboardWidth; ++x) {
robertphillips@google.com6670ab92013-05-09 19:03:48 +0000196 if (even == (x / kCheckSize) % 2) {
197 *scanline++ = 0xFFFF0000;
198 } else {
199 *scanline++ = 0x00000000;
200 }
201 }
202 }
203 }
204
205 typedef SkBenchmark INHERITED;
206};
207
208// Partial clear
209DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, false)); )
210DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, false)); )
robertphillips@google.com347fd4e2013-05-15 14:18:32 +0000211DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, false, true)); )
robertphillips@google.com6670ab92013-05-09 19:03:48 +0000212DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, false)); )
213
214// Full clear
215DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kScale_Type, true)); )
216DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, true)); )
robertphillips@google.com347fd4e2013-05-15 14:18:32 +0000217DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kTranslate_Type, true, true)); )
robertphillips@google.com6670ab92013-05-09 19:03:48 +0000218DEF_BENCH( return SkNEW_ARGS(GameBench, (p, GameBench::kRotate_Type, true)); )