• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkBenchmark.h"
9 #include "SkMatrix.h"
10 #include "SkMatrixUtils.h"
11 #include "SkRandom.h"
12 #include "SkString.h"
13 
14 class MatrixBench : public SkBenchmark {
15     SkString    fName;
16 public:
MatrixBench(const char name[])17     MatrixBench(const char name[])  {
18         fName.printf("matrix_%s", name);
19     }
20 
isSuitableFor(Backend backend)21     virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
22         return backend == kNonRendering_Backend;
23     }
24 
25     virtual void performTest() = 0;
26 
27 protected:
mulLoopCount() const28     virtual int mulLoopCount() const { return 1; }
29 
onGetName()30     virtual const char* onGetName() {
31         return fName.c_str();
32     }
33 
onDraw(const int loops,SkCanvas *)34     virtual void onDraw(const int loops, SkCanvas*) {
35         for (int i = 0; i < loops; i++) {
36             this->performTest();
37         }
38     }
39 
40 private:
41     typedef SkBenchmark INHERITED;
42 };
43 
44 // we want to stop the compiler from eliminating code that it thinks is a no-op
45 // so we have a non-static global we increment, hoping that will convince the
46 // compiler to execute everything
47 int gMatrixBench_NonStaticGlobal;
48 
49 #define always_do(pred)                     \
50     do {                                    \
51         if (pred) {                         \
52             ++gMatrixBench_NonStaticGlobal; \
53         }                                   \
54     } while (0)
55 
56 class EqualsMatrixBench : public MatrixBench {
57 public:
EqualsMatrixBench()58     EqualsMatrixBench() : INHERITED("equals") {}
59 protected:
performTest()60     virtual void performTest() {
61         SkMatrix m0, m1, m2;
62 
63         m0.reset();
64         m1.reset();
65         m2.reset();
66         always_do(m0 == m1);
67         always_do(m1 == m2);
68         always_do(m2 == m0);
69     }
70 private:
71     typedef MatrixBench INHERITED;
72 };
73 
74 class ScaleMatrixBench : public MatrixBench {
75 public:
ScaleMatrixBench()76     ScaleMatrixBench() : INHERITED("scale") {
77         fSX = fSY = 1.5f;
78         fM0.reset();
79         fM1.setScale(fSX, fSY);
80         fM2.setTranslate(fSX, fSY);
81     }
82 protected:
performTest()83     virtual void performTest() {
84         SkMatrix m;
85         m = fM0; m.preScale(fSX, fSY);
86         m = fM1; m.preScale(fSX, fSY);
87         m = fM2; m.preScale(fSX, fSY);
88     }
89 private:
90     SkMatrix fM0, fM1, fM2;
91     SkScalar fSX, fSY;
92     typedef MatrixBench INHERITED;
93 };
94 
95 // having unknown values in our arrays can throw off the timing a lot, perhaps
96 // handling NaN values is a lot slower. Anyway, this guy is just meant to put
97 // reasonable values in our arrays.
init9(T array[9])98 template <typename T> void init9(T array[9]) {
99     SkRandom rand;
100     for (int i = 0; i < 9; i++) {
101         array[i] = rand.nextSScalar1();
102     }
103 }
104 
105 // Test the performance of setConcat() non-perspective case:
106 // using floating point precision only.
107 class FloatConcatMatrixBench : public MatrixBench {
108 public:
FloatConcatMatrixBench()109     FloatConcatMatrixBench() : INHERITED("concat_floatfloat") {
110         init9(mya);
111         init9(myb);
112         init9(myr);
113     }
114 protected:
mulLoopCount() const115     virtual int mulLoopCount() const { return 4; }
116 
muladdmul(float a,float b,float c,float d,float * result)117     static inline void muladdmul(float a, float b, float c, float d,
118                                    float* result) {
119       *result = a * b + c * d;
120     }
performTest()121     virtual void performTest() {
122         const float* a = mya;
123         const float* b = myb;
124         float* r = myr;
125         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
126         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
127         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
128         r[2] += a[2];
129         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
130         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
131         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
132         r[5] += a[5];
133         r[6] = r[7] = 0.0f;
134         r[8] = 1.0f;
135     }
136 private:
137     float mya [9];
138     float myb [9];
139     float myr [9];
140     typedef MatrixBench INHERITED;
141 };
142 
SkDoubleToFloat(double x)143 static inline float SkDoubleToFloat(double x) {
144     return static_cast<float>(x);
145 }
146 
147 // Test the performance of setConcat() non-perspective case:
148 // using floating point precision but casting up to float for
149 // intermediate results during computations.
150 class FloatDoubleConcatMatrixBench : public MatrixBench {
151 public:
FloatDoubleConcatMatrixBench()152     FloatDoubleConcatMatrixBench() : INHERITED("concat_floatdouble") {
153         init9(mya);
154         init9(myb);
155         init9(myr);
156     }
157 protected:
mulLoopCount() const158     virtual int mulLoopCount() const { return 4; }
159 
muladdmul(float a,float b,float c,float d,float * result)160     static inline void muladdmul(float a, float b, float c, float d,
161                                    float* result) {
162       *result = SkDoubleToFloat((double)a * b + (double)c * d);
163     }
performTest()164     virtual void performTest() {
165         const float* a = mya;
166         const float* b = myb;
167         float* r = myr;
168         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
169         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
170         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
171         r[2] += a[2];
172         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
173         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
174         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
175         r[5] += a[5];
176         r[6] = r[7] = 0.0f;
177         r[8] = 1.0f;
178     }
179 private:
180     float mya [9];
181     float myb [9];
182     float myr [9];
183     typedef MatrixBench INHERITED;
184 };
185 
186 // Test the performance of setConcat() non-perspective case:
187 // using double precision only.
188 class DoubleConcatMatrixBench : public MatrixBench {
189 public:
DoubleConcatMatrixBench()190     DoubleConcatMatrixBench() : INHERITED("concat_double") {
191         init9(mya);
192         init9(myb);
193         init9(myr);
194     }
195 protected:
mulLoopCount() const196     virtual int mulLoopCount() const { return 4; }
197 
muladdmul(double a,double b,double c,double d,double * result)198     static inline void muladdmul(double a, double b, double c, double d,
199                                    double* result) {
200       *result = a * b + c * d;
201     }
performTest()202     virtual void performTest() {
203         const double* a = mya;
204         const double* b = myb;
205         double* r = myr;
206         muladdmul(a[0], b[0], a[1], b[3], &r[0]);
207         muladdmul(a[0], b[1], a[1], b[4], &r[1]);
208         muladdmul(a[0], b[2], a[1], b[5], &r[2]);
209         r[2] += a[2];
210         muladdmul(a[3], b[0], a[4], b[3], &r[3]);
211         muladdmul(a[3], b[1], a[4], b[4], &r[4]);
212         muladdmul(a[3], b[2], a[4], b[5], &r[5]);
213         r[5] += a[5];
214         r[6] = r[7] = 0.0;
215         r[8] = 1.0;
216     }
217 private:
218     double mya [9];
219     double myb [9];
220     double myr [9];
221     typedef MatrixBench INHERITED;
222 };
223 
224 class GetTypeMatrixBench : public MatrixBench {
225 public:
GetTypeMatrixBench()226     GetTypeMatrixBench()
227         : INHERITED("gettype") {
228         fArray[0] = (float) fRnd.nextS();
229         fArray[1] = (float) fRnd.nextS();
230         fArray[2] = (float) fRnd.nextS();
231         fArray[3] = (float) fRnd.nextS();
232         fArray[4] = (float) fRnd.nextS();
233         fArray[5] = (float) fRnd.nextS();
234         fArray[6] = (float) fRnd.nextS();
235         fArray[7] = (float) fRnd.nextS();
236         fArray[8] = (float) fRnd.nextS();
237     }
238 protected:
239     // Putting random generation of the matrix inside performTest()
240     // would help us avoid anomalous runs, but takes up 25% or
241     // more of the function time.
performTest()242     virtual void performTest() {
243         fMatrix.setAll(fArray[0], fArray[1], fArray[2],
244                        fArray[3], fArray[4], fArray[5],
245                        fArray[6], fArray[7], fArray[8]);
246         always_do(fMatrix.getType());
247         fMatrix.dirtyMatrixTypeCache();
248         always_do(fMatrix.getType());
249         fMatrix.dirtyMatrixTypeCache();
250         always_do(fMatrix.getType());
251         fMatrix.dirtyMatrixTypeCache();
252         always_do(fMatrix.getType());
253         fMatrix.dirtyMatrixTypeCache();
254         always_do(fMatrix.getType());
255         fMatrix.dirtyMatrixTypeCache();
256         always_do(fMatrix.getType());
257         fMatrix.dirtyMatrixTypeCache();
258         always_do(fMatrix.getType());
259         fMatrix.dirtyMatrixTypeCache();
260         always_do(fMatrix.getType());
261     }
262 private:
263     SkMatrix fMatrix;
264     float fArray[9];
265     SkRandom fRnd;
266     typedef MatrixBench INHERITED;
267 };
268 
269 class ScaleTransMixedMatrixBench : public MatrixBench {
270  public:
ScaleTransMixedMatrixBench()271     ScaleTransMixedMatrixBench() : INHERITED("scaletrans_mixed") {
272         fMatrix.setAll(fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(),
273                        fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(),
274                        fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1());
275         int i;
276         for (i = 0; i < kCount; i++) {
277             fSrc[i].fX = fRandom.nextSScalar1();
278             fSrc[i].fY = fRandom.nextSScalar1();
279             fDst[i].fX = fRandom.nextSScalar1();
280             fDst[i].fY = fRandom.nextSScalar1();
281         }
282     }
283  protected:
performTest()284     virtual void performTest() {
285         SkPoint* dst = fDst;
286         const SkPoint* src = fSrc;
287         int count = kCount;
288         float mx = fMatrix[SkMatrix::kMScaleX];
289         float my = fMatrix[SkMatrix::kMScaleY];
290         float tx = fMatrix[SkMatrix::kMTransX];
291         float ty = fMatrix[SkMatrix::kMTransY];
292         do {
293             dst->fY = SkScalarMulAdd(src->fY, my, ty);
294             dst->fX = SkScalarMulAdd(src->fX, mx, tx);
295             src += 1;
296             dst += 1;
297         } while (--count);
298     }
299  private:
300     enum {
301         kCount = 16
302     };
303     SkMatrix fMatrix;
304     SkPoint fSrc [kCount];
305     SkPoint fDst [kCount];
306     SkRandom fRandom;
307     typedef MatrixBench INHERITED;
308 };
309 
310 class ScaleTransDoubleMatrixBench : public MatrixBench {
311  public:
ScaleTransDoubleMatrixBench()312     ScaleTransDoubleMatrixBench() : INHERITED("scaletrans_double") {
313         init9(fMatrix);
314         int i;
315         for (i = 0; i < kCount; i++) {
316             fSrc[i].fX = fRandom.nextSScalar1();
317             fSrc[i].fY = fRandom.nextSScalar1();
318             fDst[i].fX = fRandom.nextSScalar1();
319             fDst[i].fY = fRandom.nextSScalar1();
320         }
321     }
322  protected:
performTest()323     virtual void performTest() {
324         SkPoint* dst = fDst;
325         const SkPoint* src = fSrc;
326         int count = kCount;
327         // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode
328         float mx = (float) fMatrix[SkMatrix::kMScaleX];
329         float my = (float) fMatrix[SkMatrix::kMScaleY];
330         float tx = (float) fMatrix[SkMatrix::kMTransX];
331         float ty = (float) fMatrix[SkMatrix::kMTransY];
332         do {
333             dst->fY = src->fY * my + ty;
334             dst->fX = src->fX * mx + tx;
335             src += 1;
336             dst += 1;
337         } while (--count);
338     }
339  private:
340     enum {
341         kCount = 16
342     };
343     double fMatrix [9];
344     SkPoint fSrc [kCount];
345     SkPoint fDst [kCount];
346     SkRandom fRandom;
347     typedef MatrixBench INHERITED;
348 };
349 
350 class DecomposeMatrixBench : public MatrixBench {
351 public:
DecomposeMatrixBench()352     DecomposeMatrixBench() : INHERITED("decompose") {}
353 
354 protected:
onPreDraw()355     virtual void onPreDraw() {
356         for (int i = 0; i < 10; ++i) {
357             SkScalar rot0 = (fRandom.nextBool()) ? fRandom.nextRangeF(-180, 180) : 0.0f;
358             SkScalar sx = fRandom.nextRangeF(-3000.f, 3000.f);
359             SkScalar sy = (fRandom.nextBool()) ? fRandom.nextRangeF(-3000.f, 3000.f) : sx;
360             SkScalar rot1 = fRandom.nextRangeF(-180, 180);
361             fMatrix[i].setRotate(rot0);
362             fMatrix[i].postScale(sx, sy);
363             fMatrix[i].postRotate(rot1);
364         }
365     }
performTest()366     virtual void performTest() {
367         SkPoint rotation1, scale, rotation2;
368         for (int i = 0; i < 10; ++i) {
369             (void) SkDecomposeUpper2x2(fMatrix[i], &rotation1, &scale, &rotation2);
370         }
371     }
372 private:
373     SkMatrix fMatrix[10];
374     SkRandom fRandom;
375     typedef MatrixBench INHERITED;
376 };
377 
378 class InvertMapRectMatrixBench : public MatrixBench {
379 public:
InvertMapRectMatrixBench(const char * name,int flags)380     InvertMapRectMatrixBench(const char* name, int flags)
381         : INHERITED(name)
382         , fFlags(flags) {
383         fMatrix.reset();
384         fIteration = 0;
385         if (flags & kScale_Flag) {
386             fMatrix.postScale(1.5f, 2.5f);
387         }
388         if (flags & kTranslate_Flag) {
389             fMatrix.postTranslate(1.5f, 2.5f);
390         }
391         if (flags & kRotate_Flag) {
392             fMatrix.postRotate(45.0f);
393         }
394         if (flags & kPerspective_Flag) {
395             fMatrix.setPerspX(1.5f);
396             fMatrix.setPerspY(2.5f);
397         }
398         if (0 == (flags & kUncachedTypeMask_Flag)) {
399             fMatrix.getType();
400         }
401     }
402     enum Flag {
403         kScale_Flag             = 0x01,
404         kTranslate_Flag         = 0x02,
405         kRotate_Flag            = 0x04,
406         kPerspective_Flag       = 0x08,
407         kUncachedTypeMask_Flag  = 0x10,
408     };
409 protected:
performTest()410     virtual void performTest() {
411         if (fFlags & kUncachedTypeMask_Flag) {
412             // This will invalidate the typemask without
413             // changing the matrix.
414             fMatrix.setPerspX(fMatrix.getPerspX());
415         }
416         SkMatrix inv;
417         bool invertible = fMatrix.invert(&inv);
418         SkASSERT(invertible);
419         SkRect transformedRect;
420         // an arbitrary, small, non-zero rect to transform
421         SkRect srcRect = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10));
422         if (invertible) {
423             inv.mapRect(&transformedRect, srcRect);
424         }
425     }
426 private:
427     SkMatrix fMatrix;
428     int fFlags;
429     unsigned fIteration;
430     typedef MatrixBench INHERITED;
431 };
432 
433 ///////////////////////////////////////////////////////////////////////////////
434 
435 DEF_BENCH( return new EqualsMatrixBench(); )
436 DEF_BENCH( return new ScaleMatrixBench(); )
437 DEF_BENCH( return new FloatConcatMatrixBench(); )
438 DEF_BENCH( return new FloatDoubleConcatMatrixBench(); )
439 DEF_BENCH( return new DoubleConcatMatrixBench(); )
440 DEF_BENCH( return new GetTypeMatrixBench(); )
441 DEF_BENCH( return new DecomposeMatrixBench(); )
442 
443 DEF_BENCH( return new InvertMapRectMatrixBench("invert_maprect_identity", 0); )
444 
445 DEF_BENCH(return new InvertMapRectMatrixBench(
446                                   "invert_maprect_rectstaysrect",
447                                   InvertMapRectMatrixBench::kScale_Flag |
448                                   InvertMapRectMatrixBench::kTranslate_Flag); )
449 
450 DEF_BENCH(return new InvertMapRectMatrixBench(
451                                   "invert_maprect_translate",
452                                   InvertMapRectMatrixBench::kTranslate_Flag); )
453 
454 DEF_BENCH(return new InvertMapRectMatrixBench(
455                                   "invert_maprect_nonpersp",
456                                   InvertMapRectMatrixBench::kScale_Flag |
457                                   InvertMapRectMatrixBench::kRotate_Flag |
458                                   InvertMapRectMatrixBench::kTranslate_Flag); )
459 
460 DEF_BENCH( return new InvertMapRectMatrixBench(
461                                "invert_maprect_persp",
462                                InvertMapRectMatrixBench::kPerspective_Flag); )
463 
464 DEF_BENCH( return new InvertMapRectMatrixBench(
465                            "invert_maprect_typemask_rectstaysrect",
466                            InvertMapRectMatrixBench::kUncachedTypeMask_Flag |
467                            InvertMapRectMatrixBench::kScale_Flag |
468                            InvertMapRectMatrixBench::kTranslate_Flag); )
469 
470 DEF_BENCH( return new InvertMapRectMatrixBench(
471                            "invert_maprect_typemask_nonpersp",
472                            InvertMapRectMatrixBench::kUncachedTypeMask_Flag |
473                            InvertMapRectMatrixBench::kScale_Flag |
474                            InvertMapRectMatrixBench::kRotate_Flag |
475                            InvertMapRectMatrixBench::kTranslate_Flag); )
476 
477 DEF_BENCH( return new ScaleTransMixedMatrixBench(); )
478 DEF_BENCH( return new ScaleTransDoubleMatrixBench(); )
479