Flutter Engine
The Flutter Engine
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:
23 enum Type {
27 };
28
29 enum Clear {
32 };
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;
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);
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));
const char * fName
DEF_BENCH(return new GameBench(GameBench::kTranslate_Type, GameBench::kFull_Clear, false, true, true);) class CanvasMatrixBench DEF_BENCH(return new CanvasMatrixBench(CanvasMatrixBench::kTranslate_Type))
#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,...)
Definition: SkRecorder.cpp:128
#define SkScalarFloorToScalar(x)
Definition: SkScalar.h:30
#define SkIntToScalar(x)
Definition: SkScalar.h:57
#define SK_ScalarSqrt2
Definition: SkScalar.h:20
GLenum type
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
@ kPartial_Clear
Definition: GameBench.cpp:31
void onDraw(int loops, SkCanvas *canvas) override
Definition: GameBench.cpp:93
@ kTranslate_Type
Definition: GameBench.cpp:25
@ kRotate_Type
Definition: GameBench.cpp:26
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)
Definition: SkCanvas.cpp:1673
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
virtual SkISize getBaseLayerSize() const
Definition: SkCanvas.cpp:369
@ 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)
Definition: SkCanvas.cpp:2333
int save()
Definition: SkCanvas.cpp:447
void setMatrix(const SkM44 &matrix)
Definition: SkCanvas.cpp:1349
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
Definition: SkCanvas.cpp:1720
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()
Definition: SkMatrix.cpp:1544
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[])
Definition: SkVertices.cpp:200
@ kTriangles_VertexMode
Definition: SkVertices.h:31
float SkScalar
Definition: extension.cpp:12
double y
double x
PODArray< SkColor > colors
Definition: SkRecords.h:276
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
SkSamplingOptions(SkFilterMode::kLinear))
int32_t height
int32_t width
Definition: SkRect.h:32
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition: SkRect.h:104
Definition: SkSize.h:16
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669