Flutter Engine
The Flutter Engine
ShapesBench.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2016 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"
13#include "src/base/SkRandom.h"
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <functional>
19
20using namespace skia_private;
21
22#define ENABLE_COMMAND_LINE_SHAPES_BENCH 0
23
24#if ENABLE_COMMAND_LINE_SHAPES_BENCH
25static DEFINE_string(shapesType, "mixed",
26 "Type of shape to use in ShapesBench. Must be one of: "
27 "rect, oval, rrect, mixed.");
28static DEFINE_string(innerShapesType, "none",
29 "Type of inner shape to use in ShapesBench. Must be one of: "
30 "none, rect, oval, rrect, mixed.");
31static DEFINE_int(numShapes, 10000, "Number of shapes to draw in ShapesBench.");
32static DEFINE_string(shapesSize, "32x32", "Size of shapes to draw in ShapesBench.");
33static DEFINE_bool(shapesPersp, false, "Use slight perspective tilt in ShapesBench?");
34#endif
35
36/*
37 * This class is used for several benchmarks that draw different primitive Skia shapes at various
38 * sizes. It is used to test both CPU-bound and GPU-bound rendering situations. It draws large
39 * amounts of shapes internally (rather than relying on nanobench selecting lots of loops) in order
40 * to take advantage of instanced rendering approaches.
41 */
42class ShapesBench : public Benchmark {
43public:
50 };
51
52 ShapesBench(ShapesType shapesType, ShapesType innerShapesType,
53 int numShapes, const SkISize& shapesSize, bool perspective)
54 : fShapesType(shapesType)
55 , fInnerShapesType(innerShapesType)
56 , fNumShapes(numShapes)
57 , fShapesSize(shapesSize)
58 , fPerspective(perspective) {
59 clampShapeSize();
60 }
61
62#if ENABLE_COMMAND_LINE_SHAPES_BENCH
63 ShapesBench() {
64 if (!strcmp(FLAGS_shapesType[0], "rect")) {
65 fShapesType = kRect_ShapesType;
66 } else if (!strcmp(FLAGS_shapesType[0], "oval")) {
67 fShapesType = kOval_ShapesType;
68 } else if (!strcmp(FLAGS_shapesType[0], "rrect")) {
69 fShapesType = kRRect_ShapesType;
70 } else if (!strcmp(FLAGS_shapesType[0], "mixed")) {
71 fShapesType = kMixed_ShapesType;
72 } else {
73 SkDebugf("Invalid shapesType \"%s\". Must be one of: rect, oval, rrect, mixed.",
74 FLAGS_shapesType[0]);
75 exit(-1);
76 }
77 if (!strcmp(FLAGS_innerShapesType[0], "none")) {
78 fInnerShapesType = kNone_ShapesType;
79 } else if (!strcmp(FLAGS_innerShapesType[0], "rect")) {
80 fInnerShapesType = kRect_ShapesType;
81 } else if (!strcmp(FLAGS_innerShapesType[0], "oval")) {
82 fInnerShapesType = kOval_ShapesType;
83 } else if (!strcmp(FLAGS_innerShapesType[0], "rrect")) {
84 fInnerShapesType = kRRect_ShapesType;
85 } else if (!strcmp(FLAGS_innerShapesType[0], "mixed")) {
86 fInnerShapesType = kMixed_ShapesType;
87 } else {
88 SkDebugf("Invalid innerShapesType \"%s\". Must be one of: "
89 "none, rect, oval, rrect, mixed.", FLAGS_innerShapesType[0]);
90 exit(-1);
91 }
92 if (2 != sscanf(FLAGS_shapesSize[0], "%ix%i", &fShapesSize.fWidth, &fShapesSize.fHeight)) {
93 SkDebugf("Could not parse shapesSize from \"%s\". Expected \"%%ix%%i\"\n",
94 FLAGS_shapesSize[0]);
95 exit(-1);
96 }
97
98 fNumShapes = FLAGS_numShapes;
99 fPerspective = FLAGS_shapesPersp;
100
101 clampShapeSize();
102 }
103#endif
104
105private:
106 void clampShapeSize() {
107 float maxDiagonal = static_cast<float>(std::min(kBenchWidth, kBenchHeight));
108 float diagonal = sqrtf(static_cast<float>(fShapesSize.width() * fShapesSize.width()) +
109 static_cast<float>(fShapesSize.height() * fShapesSize.height()));
110 if (diagonal > maxDiagonal) {
111 fShapesSize.fWidth = static_cast<int>(fShapesSize.width() * maxDiagonal / diagonal);
112 fShapesSize.fHeight = static_cast<int>(fShapesSize.height() * maxDiagonal / diagonal);
113 }
114 }
115
116 const char* onGetName() override {
117 const char* shapeTypeNames[] = {
118 "none", "rect", "oval", "rrect", "mixed"
119 };
120
121 fName.printf("shapes_%s", shapeTypeNames[fShapesType]);
122
123 if (kNone_ShapesType != fInnerShapesType) {
124 fName.appendf("_inner_%s", shapeTypeNames[fInnerShapesType]);
125 }
126
127 fName.appendf("_%i_%ix%i", fNumShapes, fShapesSize.width(), fShapesSize.height());
128
129 if (fPerspective) {
130 fName.append("_persp");
131 }
132
133 return fName.c_str();
134 }
135 SkISize onGetSize() override { return SkISize::Make(kBenchWidth, kBenchHeight); }
136
137 void onDelayedSetup() override {
138 SkScalar w = SkIntToScalar(fShapesSize.width());
139 SkScalar h = SkIntToScalar(fShapesSize.height());
140
141 fRect.setRect(SkRect::MakeXYWH(-w / 2, -h / 2, w, h));
142 fOval.setOval(fRect.rect());
143 fRRect.setNinePatch(fRect.rect(), w / 8, h / 13, w / 11, h / 7);
144
145 if (kNone_ShapesType != fInnerShapesType) {
146 fRect.inset(w / 7, h / 11, &fInnerRect);
147 fInnerRect.offset(w / 28, h / 44);
148 fInnerOval.setOval(fInnerRect.rect());
149 fInnerRRect.setRectXY(fInnerRect.rect(), w / 13, w / 7);
150 }
151
152 SkRandom rand;
153 fShapes.push_back_n(fNumShapes);
154 for (int i = 0; i < fNumShapes; i++) {
155 float pad = sqrtf(static_cast<float>(fShapesSize.width() * fShapesSize.width()) +
156 static_cast<float>(fShapesSize.height() * fShapesSize.height()));
157 fShapes[i].fMatrix.setTranslate(0.5f * pad + rand.nextF() * (kBenchWidth - pad),
158 0.5f * pad + rand.nextF() * (kBenchHeight - pad));
159 fShapes[i].fMatrix.preRotate(rand.nextF() * 360.0f);
160 if (fPerspective) {
161 fShapes[i].fMatrix.setPerspX(0.00015f);
162 fShapes[i].fMatrix.setPerspY(-0.00015f);
163 }
164 fShapes[i].fColor = rand.nextU() | 0xff808080;
165 }
166 for (int i = 0; i < fNumShapes; i++) {
167 // Do this in a separate loop so mixed shapes get the same random numbers during
168 // placement as non-mixed do.
169 int shapeType = fShapesType;
170 if (kMixed_ShapesType == shapeType) {
172 }
173 int innerShapeType = fInnerShapesType;
174 if (kMixed_ShapesType == innerShapeType) {
175 innerShapeType = rand.nextRangeU(kRect_ShapesType, kRRect_ShapesType);
176 }
177 if (kNone_ShapesType == innerShapeType) {
178 switch (shapeType) {
179 using namespace std;
180 using namespace std::placeholders;
181 case kRect_ShapesType:
182 fShapes[i].fDraw = bind(&SkCanvas::drawRect, _1, cref(fRect.rect()), _2);
183 break;
184 case kOval_ShapesType:
185 fShapes[i].fDraw = bind(&SkCanvas::drawOval, _1, cref(fOval.rect()), _2);
186 break;
188 fShapes[i].fDraw = bind(&SkCanvas::drawRRect, _1, cref(fRRect), _2);
189 break;
190 }
191 } else {
192 const SkRRect* outer = nullptr;
193 switch (shapeType) {
194 case kRect_ShapesType: outer = &fRect; break;
195 case kOval_ShapesType: outer = &fOval; break;
196 case kRRect_ShapesType: outer = &fRRect; break;
197 }
198 const SkRRect* inner = nullptr;
199 switch (innerShapeType) {
200 case kRect_ShapesType: inner = &fInnerRect; break;
201 case kOval_ShapesType: inner = &fInnerOval; break;
202 case kRRect_ShapesType: inner = &fInnerRRect; break;
203 }
204 fShapes[i].fDraw = std::bind(&SkCanvas::drawDRRect, std::placeholders::_1,
205 std::cref(*outer), std::cref(*inner),
206 std::placeholders::_2);
207 }
208 }
209 }
210
211 void onDraw(int loops, SkCanvas* canvas) override {
213 this->setupPaint(&paint);
214 for (int j = 0; j < loops; j++) {
215 for (int i = 0; i < fNumShapes; i++) {
216 canvas->save();
217 canvas->setMatrix(fShapes[i].fMatrix);
218 paint.setColor(fShapes[i].fColor);
219 fShapes[i].fDraw(canvas, paint);
220 canvas->restore();
221 }
222 }
223 }
224
225 static constexpr int kBenchWidth = 1000;
226 static constexpr int kBenchHeight = 1000;
227
228 struct ShapeInfo {
230 SkColor fColor;
231 std::function<void(SkCanvas*, const SkPaint&)> fDraw;
232 };
233
234 ShapesType fShapesType;
235 ShapesType fInnerShapesType;
236 int fNumShapes;
237 SkISize fShapesSize;
238 bool fPerspective;
239 SkString fName;
240 SkRRect fRect;
241 SkRRect fOval;
242 SkRRect fRRect;
243 SkRRect fInnerRect;
244 SkRRect fInnerOval;
245 SkRRect fInnerRRect;
246 TArray<ShapeInfo> fShapes;
247
248
249 using INHERITED = Benchmark;
250};
251
252#if ENABLE_COMMAND_LINE_SHAPES_BENCH
253DEF_BENCH(return new ShapesBench;)
254#else
255// Small primitives (CPU bound, in theory):
257 10000, SkISize::Make(32, 32), false);)
259 10000, SkISize::Make(32, 32), false);)
261 10000, SkISize::Make(32, 33), false);)
263 10000, SkISize::Make(32, 32), false);)
265 10000, SkISize::Make(32, 33), false);)
266
267// Large primitives (GPU bound, in theory):
269 100, SkISize::Make(500, 500), false);)
271 100, SkISize::Make(500, 500), false);)
273 100, SkISize::Make(500, 501), false);)
275 100, SkISize::Make(500, 500), false);)
277 100, SkISize::Make(500, 501), false);)
278
279// Donuts (small and large). These fall-back to path rendering due to non-orthogonal rotation
280// making them quite slow. Thus, reduce the counts substantially:
282 500, SkISize::Make(32, 32), false);)
284 500, SkISize::Make(32, 32), false);)
286 50, SkISize::Make(500, 500), false);)
288 50, SkISize::Make(500, 500), false);)
289#endif
#define DEF_BENCH(code)
Definition: Benchmark.h:20
#define DEFINE_string(name, defaultValue, helpString)
DEFINE_int(gpuThreads, 2, "Create this many extra threads to assist with GPU work, " "including software path rendering. Defaults to two.")
SkMatrix fMatrix
Definition: FillRRectOp.cpp:74
DEFINE_bool(verboseFontMgr, false, "FontMgr will be very verbose.")
uint32_t SkColor
Definition: SkColor.h:37
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkIntToScalar(x)
Definition: SkScalar.h:57
virtual void setupPaint(SkPaint *paint)
Definition: Benchmark.cpp:55
ShapesBench(ShapesType shapesType, ShapesType innerShapesType, int numShapes, const SkISize &shapesSize, bool perspective)
Definition: ShapesBench.cpp:52
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawOval(const SkRect &oval, const SkPaint &paint)
Definition: SkCanvas.cpp:1698
void restore()
Definition: SkCanvas.cpp:461
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
Definition: SkCanvas.cpp:1705
int save()
Definition: SkCanvas.cpp:447
void setMatrix(const SkM44 &matrix)
Definition: SkCanvas.cpp:1349
void drawDRRect(const SkRRect &outer, const SkRRect &inner, const SkPaint &paint)
Definition: SkCanvas.cpp:1645
const SkRect & rect() const
Definition: SkRRect.h:264
void inset(SkScalar dx, SkScalar dy, SkRRect *dst) const
Definition: SkRRect.cpp:562
void setOval(const SkRect &oval)
Definition: SkRRect.cpp:30
void offset(SkScalar dx, SkScalar dy)
Definition: SkRRect.h:387
void setRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.cpp:52
void setNinePatch(const SkRect &rect, SkScalar leftRad, SkScalar topRad, SkScalar rightRad, SkScalar bottomRad)
Definition: SkRRect.cpp:115
void setRect(const SkRect &rect)
Definition: SkRRect.h:126
uint32_t nextU()
Definition: SkRandom.h:42
float nextF()
Definition: SkRandom.h:55
uint32_t nextRangeU(uint32_t min, uint32_t max)
Definition: SkRandom.h:80
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:534
void append(const char text[])
Definition: SkString.h:203
const char * c_str() const
Definition: SkString.h:133
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:550
T * push_back_n(int n)
Definition: SkTArray.h:267
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
Dart_NativeFunction function
Definition: fuchsia.cc:51
static float min(float r, float g, float b)
Definition: hsl.cpp:48
exit(kErrorExitCode)
Definition: ref_ptr.h:256
SkScalar w
SkScalar h
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659