Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GameBench.cpp
Go to the documentation of this file.
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
8#include "bench/Benchmark.h"
12#include "include/core/SkM44.h"
17#include "src/base/SkRandom.h"
18
19// This bench simulates the calls Skia sees from various HTML5 canvas
20// game bench marks
21class GameBench : public Benchmark {
22public:
28
33
35 bool aligned = false, bool useAtlas = false,
36 bool useDrawVertices = false)
37 : fType(type)
38 , fClear(clear)
39 , fAligned(aligned)
40 , fUseAtlas(useAtlas)
41 , fUseDrawVertices(useDrawVertices)
42 , fName("game")
43 , fNumSaved(0)
44 , fInitialized(false) {
45
46 switch (fType) {
47 case kScale_Type:
48 fName.append("_scale");
49 break;
50 case kTranslate_Type:
51 fName.append("_trans");
52 break;
53 case kRotate_Type:
54 fName.append("_rot");
55 break;
56 }
57
58 if (aligned) {
59 fName.append("_aligned");
60 }
61
62 if (kPartial_Clear == clear) {
63 fName.append("_partial");
64 } else {
65 fName.append("_full");
66 }
67
68 if (useAtlas) {
69 fName.append("_atlas");
70 }
71
72 if (useDrawVertices) {
73 fName.append("_drawVerts");
74 }
75
76 // It's HTML 5 canvas, so always AA
77 fName.append("_aa");
78 }
79
80protected:
81 const char* onGetName() override {
82 return fName.c_str();
83 }
84
85 void onDelayedSetup() override {
86 if (!fInitialized) {
87 this->makeCheckerboard();
88 this->makeAtlas();
89 fInitialized = true;
90 }
91 }
92
93 void onDraw(int loops, SkCanvas* canvas) override {
94 SkRandom scaleRand;
95 SkRandom transRand;
96 SkRandom rotRand;
97
98 int width, height;
99 if (fUseAtlas) {
100 width = kAtlasCellWidth;
101 height = kAtlasCellHeight;
102 } else {
103 width = kCheckerboardWidth;
104 height = kCheckerboardHeight;
105 }
106
107 SkPaint clearPaint;
108 clearPaint.setColor(0xFF000000);
109 clearPaint.setAntiAlias(true);
110
111 SkISize size = canvas->getBaseLayerSize();
112
113 SkScalar maxTransX, maxTransY;
114
115 if (kScale_Type == fType) {
116 maxTransX = size.fWidth - (1.5f * width);
117 maxTransY = size.fHeight - (1.5f * height);
118 } else if (kTranslate_Type == fType) {
119 maxTransX = SkIntToScalar(size.fWidth - width);
120 maxTransY = SkIntToScalar(size.fHeight - height);
121 } else {
122 SkASSERT(kRotate_Type == fType);
123 // Yes, some rotations will be off the top and left sides
124 maxTransX = size.fWidth - SK_ScalarSqrt2 * height;
125 maxTransY = size.fHeight - SK_ScalarSqrt2 * height;
126 }
127
128 SkMatrix mat;
129 SkRect dst = { 0, 0, SkIntToScalar(width), SkIntToScalar(height) };
130 SkRect clearRect = { -1.0f, -1.0f, width+1.0f, height+1.0f };
131 SkPoint verts[4] = { // for drawVertices path
132 { 0, 0 },
133 { 0, SkIntToScalar(height) },
135 { SkIntToScalar(width), 0 }
136 };
137 uint16_t indices[6] = { 0, 1, 2, 0, 2, 3 };
138
139 SkPaint p;
140 p.setColor(0xFF000000);
141
142 SkPaint p2; // for drawVertices path
143 p2.setColor(0xFF000000);
145
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]);
152
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]);
157 }
158
159 canvas->concat(mat);
160 canvas->drawRect(clearRect, clearPaint);
161 }
162 } else {
163 canvas->clear(0xFF000000);
164 }
165
166 fNumSaved = 0;
167 }
168
169 SkASSERT(fNumSaved < kNumBeforeClear);
170
171 canvas->setMatrix(SkMatrix::I());
172
173 fSaved[fNumSaved][0] = transRand.nextRangeScalar(0.0f, maxTransX);
174 fSaved[fNumSaved][1] = transRand.nextRangeScalar(0.0f, maxTransY);
175 if (fAligned) {
176 // make the translations integer aligned
177 fSaved[fNumSaved][0] = SkScalarFloorToScalar(fSaved[fNumSaved][0]);
178 fSaved[fNumSaved][1] = SkScalarFloorToScalar(fSaved[fNumSaved][1]);
179 }
180
181 mat.setTranslate(fSaved[fNumSaved][0], fSaved[fNumSaved][1]);
182
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]);
189 }
190
191 canvas->concat(mat);
192 if (fUseAtlas) {
193 const int curCell = i % (kNumAtlasedX * kNumAtlasedY);
194 SkRect src = SkRect::Make(
195 fAtlasRects[curCell % (kNumAtlasedX)][curCell / (kNumAtlasedX)]);
196
197 if (fUseDrawVertices) {
198 SkPoint uvs[4] = {
199 { SkIntToScalar(src.fLeft), SkIntToScalar(src.fBottom) },
200 { SkIntToScalar(src.fLeft), SkIntToScalar(src.fTop) },
201 { SkIntToScalar(src.fRight), SkIntToScalar(src.fTop) },
202 { SkIntToScalar(src.fRight), SkIntToScalar(src.fBottom) },
203 };
205 4, verts, uvs, nullptr, 6, indices),
207 } else {
208 canvas->drawImageRect(fAtlas, src, dst, SkSamplingOptions(), &p,
210 }
211 } else {
212 canvas->drawImageRect(fCheckerboard, dst, SkSamplingOptions(), &p);
213 }
214 }
215 }
216
217private:
218 static const int kCheckerboardWidth = 64;
219 static const int kCheckerboardHeight = 128;
220
221 static const int kAtlasCellWidth = 48;
222 static const int kAtlasCellHeight = 36;
223 static const int kNumAtlasedX = 5;
224 static const int kNumAtlasedY = 5;
225 static const int kAtlasSpacer = 2;
226 static const int kTotAtlasWidth = kNumAtlasedX * kAtlasCellWidth +
227 (kNumAtlasedX+1) * kAtlasSpacer;
228 static const int kTotAtlasHeight = kNumAtlasedY * kAtlasCellHeight +
229 (kNumAtlasedY+1) * kAtlasSpacer;
230 static const int kNumBeforeClear = 100;
231
232 Type fType;
233 Clear fClear;
234 bool fAligned;
235 bool fUseAtlas;
236 bool fUseDrawVertices;
237 SkString fName;
238 int fNumSaved; // num draws stored in 'fSaved'
239 bool fInitialized;
240
241 // 0 & 1 are always x & y translate. 2 is either scale or rotate.
242 SkScalar fSaved[kNumBeforeClear][3];
243
244 sk_sp<SkImage> fCheckerboard, fAtlas;
245 SkIRect fAtlasRects[kNumAtlasedX][kNumAtlasedY];
246
247 // Note: the resulting checker board has transparency
248 void makeCheckerboard() {
249 static int kCheckSize = 16;
250
251 SkBitmap bm;
252 bm.allocN32Pixels(kCheckerboardWidth, kCheckerboardHeight);
253 for (int y = 0; y < kCheckerboardHeight; ++y) {
254 int even = (y / kCheckSize) % 2;
255
256 SkPMColor* scanline = bm.getAddr32(0, y);
257
258 for (int x = 0; x < kCheckerboardWidth; ++x) {
259 if (even == (x / kCheckSize) % 2) {
260 *scanline++ = 0xFFFF0000;
261 } else {
262 *scanline++ = 0x00000000;
263 }
264 }
265 }
266 fCheckerboard = bm.asImage();
267 }
268
269 // Note: the resulting atlas has transparency
270 void makeAtlas() {
271 SkRandom rand;
272
273 SkColor colors[kNumAtlasedX][kNumAtlasedY];
274
275 for (int y = 0; y < kNumAtlasedY; ++y) {
276 for (int x = 0; x < kNumAtlasedX; ++x) {
277 colors[x][y] = rand.nextU() | 0xff000000;
278 fAtlasRects[x][y] = SkIRect::MakeXYWH(kAtlasSpacer + x * (kAtlasCellWidth + kAtlasSpacer),
279 kAtlasSpacer + y * (kAtlasCellHeight + kAtlasSpacer),
280 kAtlasCellWidth,
281 kAtlasCellHeight);
282 }
283 }
284
285 SkBitmap bm;
286 bm.allocN32Pixels(kTotAtlasWidth, kTotAtlasHeight);
287
288 for (int y = 0; y < kTotAtlasHeight; ++y) {
289 int colorY = y / (kAtlasCellHeight + kAtlasSpacer);
290 bool inColorY = (y % (kAtlasCellHeight + kAtlasSpacer)) >= kAtlasSpacer;
291
292 SkPMColor* scanline = bm.getAddr32(0, y);
293
294 for (int x = 0; x < kTotAtlasWidth; ++x, ++scanline) {
295 int colorX = x / (kAtlasCellWidth + kAtlasSpacer);
296 bool inColorX = (x % (kAtlasCellWidth + kAtlasSpacer)) >= kAtlasSpacer;
297
298 if (inColorX && inColorY) {
299 SkASSERT(colorX < kNumAtlasedX && colorY < kNumAtlasedY);
300 *scanline = colors[colorX][colorY];
301 } else {
302 *scanline = 0x00000000;
303 }
304 }
305 }
306 fAtlas = bm.asImage();
307 }
308
309 using INHERITED = Benchmark;
310};
311
312// Partial clear
317
318// Full clear
323
324// Atlased
326DEF_BENCH(return new GameBench(
328
329
330class CanvasMatrixBench : public Benchmark {
332public:
333 enum Type {
334 kTranslate_Type,
335 kScale_Type,
336 k2x3_Type,
337 k3x3_Type,
338 k4x4_Type,
339 };
340 Type fType;
341
342 CanvasMatrixBench(Type t) : fType(t) {
343 fName.set("canvas_matrix");
344 switch (fType) {
345 case kTranslate_Type: fName.append("_trans"); break;
346 case kScale_Type: fName.append("_scale"); break;
347 case k2x3_Type: fName.append("_2x3"); break;
348 case k3x3_Type: fName.append("_3x3"); break;
349 case k4x4_Type: fName.append("_4x4"); break;
350 }
351 }
352
353protected:
354 const char* onGetName() override {
355 return fName.c_str();
356 }
357
358 void onDraw(int loops, SkCanvas* canvas) override {
359 SkMatrix m;
360 m.setRotate(1);
361 if (fType == k3x3_Type) {
362 m[7] = 0.0001f;
363 }
364 SkM44 m4(m);
365
366 for (int i = 0; i < loops; ++i) {
367 canvas->save();
368 for (int j = 0; j < 10000; ++j) {
369 switch (fType) {
370 case kTranslate_Type: canvas->translate(0.0001f, 0.0001f); break;
371 case kScale_Type: canvas->scale(1.0001f, 0.9999f); break;
372 case k2x3_Type: canvas->concat(m); break;
373 case k3x3_Type: canvas->concat(m); break;
374 case k4x4_Type: canvas->concat(m4); break;
375 }
376 }
377 canvas->restore();
378 }
379 }
380
381private:
382 using INHERITED = Benchmark;
383};
384
385DEF_BENCH(return new CanvasMatrixBench(CanvasMatrixBench::kTranslate_Type));
386DEF_BENCH(return new CanvasMatrixBench(CanvasMatrixBench::kScale_Type));
387DEF_BENCH(return new CanvasMatrixBench(CanvasMatrixBench::k2x3_Type));
388DEF_BENCH(return new CanvasMatrixBench(CanvasMatrixBench::k3x3_Type));
389DEF_BENCH(return new CanvasMatrixBench(CanvasMatrixBench::k4x4_Type));
#define DEF_BENCH(code)
Definition Benchmark.h:20
const char * fName
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kModulate
r = s*d
uint32_t SkColor
Definition SkColor.h:37
uint32_t SkPMColor
Definition SkColor.h:205
#define INHERITED(method,...)
#define SkScalarFloorToScalar(x)
Definition SkScalar.h:30
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define SK_ScalarSqrt2
Definition SkScalar.h:20
GameBench(Type type, Clear clear, bool aligned=false, bool useAtlas=false, bool useDrawVertices=false)
Definition GameBench.cpp:34
const char * onGetName() override
Definition GameBench.cpp:81
void onDraw(int loops, SkCanvas *canvas) override
Definition GameBench.cpp:93
@ kTranslate_Type
Definition GameBench.cpp:25
void onDelayedSetup() override
Definition GameBench.cpp:85
sk_sp< SkImage > asImage() const
Definition SkBitmap.cpp:645
void allocN32Pixels(int width, int height, bool isOpaque=false)
Definition SkBitmap.cpp:232
uint32_t * getAddr32(int x, int y) const
Definition SkBitmap.h:1260
void drawRect(const SkRect &rect, const SkPaint &paint)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
virtual SkISize getBaseLayerSize() const
Definition SkCanvas.cpp:373
@ kFast_SrcRectConstraint
sample outside bounds; faster
Definition SkCanvas.h:1543
void clear(SkColor color)
Definition SkCanvas.h:1199
void drawImageRect(const SkImage *, const SkRect &src, const SkRect &dst, const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
int save()
Definition SkCanvas.cpp:451
void setMatrix(const SkM44 &matrix)
void scale(SkScalar sx, SkScalar sy)
void concat(const SkMatrix &matrix)
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition SkImage.cpp:179
Definition SkM44.h:150
SkMatrix & setTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:254
static const SkMatrix & I()
SkMatrix & preRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:462
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:315
void setColor(SkColor color)
Definition SkPaint.cpp:119
void setAntiAlias(bool aa)
Definition SkPaint.h:170
void setShader(sk_sp< SkShader > shader)
uint32_t nextU()
Definition SkRandom.h:42
SkScalar nextRangeScalar(SkScalar min, SkScalar max)
Definition SkRandom.h:106
void append(const char text[])
Definition SkString.h:203
const char * c_str() const
Definition SkString.h:133
static sk_sp< SkVertices > MakeCopy(VertexMode mode, int vertexCount, const SkPoint positions[], const SkPoint texs[], const SkColor colors[], int indexCount, const uint16_t indices[])
@ kTriangles_VertexMode
Definition SkVertices.h:31
float SkScalar
Definition extension.cpp:12
double y
double x
PODArray< SkColor > colors
Definition SkRecords.h:276
int32_t height
int32_t width
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
static SkRect Make(const SkISize &size)
Definition SkRect.h:669