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