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