1 /*
2 * Copyright 2011 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 #include "bench/Benchmark.h"
8 #include "include/core/SkMatrix.h"
9 #include "include/core/SkString.h"
10 #include "include/utils/SkRandom.h"
11 #include "src/core/SkMatrixUtils.h"
12
13 class MatrixBench : public Benchmark {
14 SkString fName;
15 public:
MatrixBench(const char name[])16 MatrixBench(const char name[]) {
17 fName.printf("matrix_%s", name);
18 }
19
isSuitableFor(Backend backend)20 bool isSuitableFor(Backend backend) override {
21 return backend == kNonRendering_Backend;
22 }
23
24 virtual void performTest() = 0;
25
26 protected:
mulLoopCount() const27 virtual int mulLoopCount() const { return 1; }
28
onGetName()29 const char* onGetName() override {
30 return fName.c_str();
31 }
32
onDraw(int loops,SkCanvas *)33 void onDraw(int loops, SkCanvas*) override {
34 for (int i = 0; i < loops; i++) {
35 this->performTest();
36 }
37 }
38
39 private:
40 using INHERITED = Benchmark;
41 };
42
43
44 class EqualsMatrixBench : public MatrixBench {
45 public:
EqualsMatrixBench()46 EqualsMatrixBench() : INHERITED("equals") {}
47 protected:
performTest()48 void performTest() override {
49 SkMatrix m0, m1, m2;
50
51 m0.reset();
52 m1.reset();
53 m2.reset();
54
55 // xor into a volatile prevents these comparisons from being optimized away.
56 SK_MAYBE_UNUSED volatile bool junk = false;
57 junk ^= (m0 == m1);
58 junk ^= (m1 == m2);
59 junk ^= (m2 == m0);
60 }
61 private:
62 using INHERITED = MatrixBench;
63 };
64
65 class ScaleMatrixBench : public MatrixBench {
66 public:
ScaleMatrixBench()67 ScaleMatrixBench() : INHERITED("scale") {
68 fSX = fSY = 1.5f;
69 fM0.reset();
70 fM1.setScale(fSX, fSY);
71 fM2.setTranslate(fSX, fSY);
72 }
73 protected:
performTest()74 void performTest() override {
75 SkMatrix m;
76 m = fM0; m.preScale(fSX, fSY);
77 m = fM1; m.preScale(fSX, fSY);
78 m = fM2; m.preScale(fSX, fSY);
79 }
80 private:
81 SkMatrix fM0, fM1, fM2;
82 SkScalar fSX, fSY;
83 using INHERITED = MatrixBench;
84 };
85
86 // having unknown values in our arrays can throw off the timing a lot, perhaps
87 // handling NaN values is a lot slower. Anyway, this is just meant to put
88 // reasonable values in our arrays.
init9(T array[9])89 template <typename T> void init9(T array[9]) {
90 SkRandom rand;
91 for (int i = 0; i < 9; i++) {
92 array[i] = rand.nextSScalar1();
93 }
94 }
95
96 class GetTypeMatrixBench : public MatrixBench {
97 public:
GetTypeMatrixBench()98 GetTypeMatrixBench()
99 : INHERITED("gettype") {
100 fArray[0] = (float) fRnd.nextS();
101 fArray[1] = (float) fRnd.nextS();
102 fArray[2] = (float) fRnd.nextS();
103 fArray[3] = (float) fRnd.nextS();
104 fArray[4] = (float) fRnd.nextS();
105 fArray[5] = (float) fRnd.nextS();
106 fArray[6] = (float) fRnd.nextS();
107 fArray[7] = (float) fRnd.nextS();
108 fArray[8] = (float) fRnd.nextS();
109 }
110 protected:
111 // Putting random generation of the matrix inside performTest()
112 // would help us avoid anomalous runs, but takes up 25% or
113 // more of the function time.
performTest()114 void performTest() override {
115 fMatrix.setAll(fArray[0], fArray[1], fArray[2],
116 fArray[3], fArray[4], fArray[5],
117 fArray[6], fArray[7], fArray[8]);
118 // xoring into a volatile prevents the compiler from optimizing these away
119 SK_MAYBE_UNUSED volatile int junk = 0;
120 junk ^= (fMatrix.getType());
121 fMatrix.dirtyMatrixTypeCache();
122 junk ^= (fMatrix.getType());
123 fMatrix.dirtyMatrixTypeCache();
124 junk ^= (fMatrix.getType());
125 fMatrix.dirtyMatrixTypeCache();
126 junk ^= (fMatrix.getType());
127 fMatrix.dirtyMatrixTypeCache();
128 junk ^= (fMatrix.getType());
129 fMatrix.dirtyMatrixTypeCache();
130 junk ^= (fMatrix.getType());
131 fMatrix.dirtyMatrixTypeCache();
132 junk ^= (fMatrix.getType());
133 fMatrix.dirtyMatrixTypeCache();
134 junk ^= (fMatrix.getType());
135 }
136 private:
137 SkMatrix fMatrix;
138 float fArray[9];
139 SkRandom fRnd;
140 using INHERITED = MatrixBench;
141 };
142
143 class DecomposeMatrixBench : public MatrixBench {
144 public:
DecomposeMatrixBench()145 DecomposeMatrixBench() : INHERITED("decompose") {}
146
147 protected:
onDelayedSetup()148 void onDelayedSetup() override {
149 for (int i = 0; i < 10; ++i) {
150 SkScalar rot0 = (fRandom.nextBool()) ? fRandom.nextRangeF(-180, 180) : 0.0f;
151 SkScalar sx = fRandom.nextRangeF(-3000.f, 3000.f);
152 SkScalar sy = (fRandom.nextBool()) ? fRandom.nextRangeF(-3000.f, 3000.f) : sx;
153 SkScalar rot1 = fRandom.nextRangeF(-180, 180);
154 fMatrix[i].setRotate(rot0);
155 fMatrix[i].postScale(sx, sy);
156 fMatrix[i].postRotate(rot1);
157 }
158 }
performTest()159 void performTest() override {
160 SkPoint rotation1, scale, rotation2;
161 for (int i = 0; i < 10; ++i) {
162 (void) SkDecomposeUpper2x2(fMatrix[i], &rotation1, &scale, &rotation2);
163 }
164 }
165 private:
166 SkMatrix fMatrix[10];
167 SkRandom fRandom;
168 using INHERITED = MatrixBench;
169 };
170
171 class InvertMapRectMatrixBench : public MatrixBench {
172 public:
InvertMapRectMatrixBench(const char * name,int flags)173 InvertMapRectMatrixBench(const char* name, int flags)
174 : INHERITED(name)
175 , fFlags(flags) {
176 fMatrix.reset();
177 fIteration = 0;
178 if (flags & kScale_Flag) {
179 fMatrix.postScale(1.5f, 2.5f);
180 }
181 if (flags & kTranslate_Flag) {
182 fMatrix.postTranslate(1.5f, 2.5f);
183 }
184 if (flags & kRotate_Flag) {
185 fMatrix.postRotate(45.0f);
186 }
187 if (flags & kPerspective_Flag) {
188 fMatrix.setPerspX(1.5f);
189 fMatrix.setPerspY(2.5f);
190 }
191 if (0 == (flags & kUncachedTypeMask_Flag)) {
192 fMatrix.getType();
193 }
194 }
195 enum Flag {
196 kScale_Flag = 0x01,
197 kTranslate_Flag = 0x02,
198 kRotate_Flag = 0x04,
199 kPerspective_Flag = 0x08,
200 kUncachedTypeMask_Flag = 0x10,
201 };
202 protected:
performTest()203 void performTest() override {
204 if (fFlags & kUncachedTypeMask_Flag) {
205 // This will invalidate the typemask without
206 // changing the matrix.
207 fMatrix.setPerspX(fMatrix.getPerspX());
208 }
209 SkMatrix inv;
210 bool invertible = fMatrix.invert(&inv);
211 SkASSERT(invertible);
212 SkRect transformedRect;
213 // an arbitrary, small, non-zero rect to transform
214 SkRect srcRect = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10));
215 if (invertible) {
216 inv.mapRect(&transformedRect, srcRect);
217 }
218 }
219 private:
220 SkMatrix fMatrix;
221 int fFlags;
222 unsigned fIteration;
223 using INHERITED = MatrixBench;
224 };
225
226 ///////////////////////////////////////////////////////////////////////////////
227
228 DEF_BENCH( return new EqualsMatrixBench(); )
DEF_BENCH(return new ScaleMatrixBench ();)229 DEF_BENCH( return new ScaleMatrixBench(); )
230 DEF_BENCH( return new GetTypeMatrixBench(); )
231 DEF_BENCH( return new DecomposeMatrixBench(); )
232
233 DEF_BENCH( return new InvertMapRectMatrixBench("invert_maprect_identity", 0); )
234
235 DEF_BENCH(return new InvertMapRectMatrixBench(
236 "invert_maprect_rectstaysrect",
237 InvertMapRectMatrixBench::kScale_Flag |
238 InvertMapRectMatrixBench::kTranslate_Flag); )
239
240 DEF_BENCH(return new InvertMapRectMatrixBench(
241 "invert_maprect_translate",
242 InvertMapRectMatrixBench::kTranslate_Flag); )
243
244 DEF_BENCH(return new InvertMapRectMatrixBench(
245 "invert_maprect_nonpersp",
246 InvertMapRectMatrixBench::kScale_Flag |
247 InvertMapRectMatrixBench::kRotate_Flag |
248 InvertMapRectMatrixBench::kTranslate_Flag); )
249
250 DEF_BENCH( return new InvertMapRectMatrixBench(
251 "invert_maprect_persp",
252 InvertMapRectMatrixBench::kPerspective_Flag); )
253
254 DEF_BENCH( return new InvertMapRectMatrixBench(
255 "invert_maprect_typemask_rectstaysrect",
256 InvertMapRectMatrixBench::kUncachedTypeMask_Flag |
257 InvertMapRectMatrixBench::kScale_Flag |
258 InvertMapRectMatrixBench::kTranslate_Flag); )
259
260 DEF_BENCH( return new InvertMapRectMatrixBench(
261 "invert_maprect_typemask_nonpersp",
262 InvertMapRectMatrixBench::kUncachedTypeMask_Flag |
263 InvertMapRectMatrixBench::kScale_Flag |
264 InvertMapRectMatrixBench::kRotate_Flag |
265 InvertMapRectMatrixBench::kTranslate_Flag); )
266
267 ///////////////////////////////////////////////////////////////////////////////
268
269 static SkMatrix make_trans() { return SkMatrix::Translate(2, 3); }
make_scale()270 static SkMatrix make_scale() { SkMatrix m(make_trans()); m.postScale(1.5f, 0.5f); return m; }
make_afine()271 static SkMatrix make_afine() { SkMatrix m(make_trans()); m.postRotate(15); return m; }
272
273 class MapPointsMatrixBench : public MatrixBench {
274 protected:
275 SkMatrix fM;
276 enum {
277 N = 32
278 };
279 SkPoint fSrc[N], fDst[N];
280 public:
MapPointsMatrixBench(const char name[],const SkMatrix & m)281 MapPointsMatrixBench(const char name[], const SkMatrix& m)
282 : MatrixBench(name), fM(m)
283 {
284 SkRandom rand;
285 for (int i = 0; i < N; ++i) {
286 fSrc[i].set(rand.nextSScalar1(), rand.nextSScalar1());
287 }
288 }
289
performTest()290 void performTest() override {
291 for (int i = 0; i < 1000000; ++i) {
292 fM.mapPoints(fDst, fSrc, N);
293 }
294 }
295 };
296 DEF_BENCH( return new MapPointsMatrixBench("mappoints_identity", SkMatrix::I()); )
297 DEF_BENCH( return new MapPointsMatrixBench("mappoints_trans", make_trans()); )
298 DEF_BENCH( return new MapPointsMatrixBench("mappoints_scale", make_scale()); )
299 DEF_BENCH( return new MapPointsMatrixBench("mappoints_affine", make_afine()); )
300
301 ///////////////////////////////////////////////////////////////////////////////
302
303 class MapRectMatrixBench : public MatrixBench {
304 SkMatrix fM;
305 SkRect fR;
306 bool fScaleTrans;
307
308 enum { MEGA_LOOP = 1000 * 1000 };
309 public:
MapRectMatrixBench(const char name[],bool scale_trans)310 MapRectMatrixBench(const char name[], bool scale_trans)
311 : MatrixBench(name), fScaleTrans(scale_trans)
312 {
313 fM.setScale(2, 3);
314 fM.postTranslate(1, 2);
315
316 fR.setLTRB(10, 10, 100, 200);
317 }
318
performTest()319 void performTest() override {
320 SkRect dst;
321 if (fScaleTrans) {
322 for (int i = 0; i < MEGA_LOOP; ++i) {
323 fM.mapRectScaleTranslate(&dst, fR);
324 }
325 } else {
326 for (int i = 0; i < MEGA_LOOP; ++i) {
327 fM.mapRect(&dst, fR);
328 }
329 }
330 }
331 };
332 DEF_BENCH( return new MapRectMatrixBench("maprect", false); )
333 DEF_BENCH( return new MapRectMatrixBench("maprectscaletrans", true); )
334