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     typedef Benchmark INHERITED;
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         volatile bool junk = false;
57         junk ^= (m0 == m1);
58         junk ^= (m1 == m2);
59         junk ^= (m2 == m0);
60     }
61 private:
62     typedef MatrixBench INHERITED;
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     typedef MatrixBench INHERITED;
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 guy 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         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     typedef MatrixBench INHERITED;
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     typedef MatrixBench INHERITED;
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     typedef MatrixBench INHERITED;
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::MakeTrans(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