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