blob: dce035857c7c0bd587cdc82b42237d81d9790b28 [file] [log] [blame]
reed@google.com3fb51872011-06-01 15:11:22 +00001#include "SkBenchmark.h"
2#include "SkMatrix.h"
tomhudson@google.com7b4e1072011-06-03 19:16:56 +00003#include "SkRandom.h"
reed@google.com3fb51872011-06-01 15:11:22 +00004#include "SkString.h"
5
6class MatrixBench : public SkBenchmark {
7 SkString fName;
8 enum { N = 100000 };
9public:
10 MatrixBench(void* param, const char name[]) : INHERITED(param) {
11 fName.printf("matrix_%s", name);
12 }
13
14 virtual void performTest() = 0;
15
16protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +000017 virtual int mulLoopCount() const { return 1; }
18
reed@google.com3fb51872011-06-01 15:11:22 +000019 virtual const char* onGetName() {
20 return fName.c_str();
21 }
22
23 virtual void onDraw(SkCanvas* canvas) {
reed@google.comcbefd7d2011-06-06 13:31:30 +000024 int n = N * this->mulLoopCount();
25 for (int i = 0; i < n; i++) {
reed@google.com3fb51872011-06-01 15:11:22 +000026 this->performTest();
27 }
28 }
29
30private:
31 typedef SkBenchmark INHERITED;
32};
33
34// we want to stop the compiler from eliminating code that it thinks is a no-op
35// so we have a non-static global we increment, hoping that will convince the
36// compiler to execute everything
37int gMatrixBench_NonStaticGlobal;
38
39#define always_do(pred) \
40 do { \
41 if (pred) { \
42 ++gMatrixBench_NonStaticGlobal; \
43 } \
44 } while (0)
45
46class EqualsMatrixBench : public MatrixBench {
47public:
48 EqualsMatrixBench(void* param) : INHERITED(param, "equals") {}
49protected:
50 virtual void performTest() {
51 SkMatrix m0, m1, m2;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +000052
reed@google.com3fb51872011-06-01 15:11:22 +000053 m0.reset();
54 m1.reset();
55 m2.reset();
56 always_do(m0 == m1);
57 always_do(m1 == m2);
58 always_do(m2 == m0);
59 always_do(m0.getType());
60 always_do(m1.getType());
61 always_do(m2.getType());
62 }
63private:
64 typedef MatrixBench INHERITED;
65};
66
67class ScaleMatrixBench : public MatrixBench {
68public:
69 ScaleMatrixBench(void* param) : INHERITED(param, "scale") {
bungeman@google.com20809002011-06-08 19:38:53 +000070 fSX = fSY = SkFloatToScalar(1.5f);
reed@google.com3fb51872011-06-01 15:11:22 +000071 fM0.reset();
72 fM1.setScale(fSX, fSY);
73 fM2.setTranslate(fSX, fSY);
reed@google.com3fb51872011-06-01 15:11:22 +000074 }
75protected:
76 virtual void performTest() {
77 SkMatrix m;
78 m = fM0; m.preScale(fSX, fSY);
79 m = fM1; m.preScale(fSX, fSY);
80 m = fM2; m.preScale(fSX, fSY);
81 }
82private:
83 SkMatrix fM0, fM1, fM2;
84 SkScalar fSX, fSY;
85 typedef MatrixBench INHERITED;
86};
87
reed@google.come0dcde72011-06-06 13:20:29 +000088// having unknown values in our arrays can throw off the timing a lot, perhaps
89// handling NaN values is a lot slower. Anyway, this guy is just meant to put
90// reasonable values in our arrays.
91template <typename T> void init9(T array[9]) {
92 SkRandom rand;
93 for (int i = 0; i < 9; i++) {
94 array[i] = rand.nextSScalar1();
95 }
96}
97
tomhudson@google.com7b4e1072011-06-03 19:16:56 +000098// Test the performance of setConcat() non-perspective case:
99// using floating point precision only.
100class FloatConcatMatrixBench : public MatrixBench {
101public:
reed@google.come0dcde72011-06-06 13:20:29 +0000102 FloatConcatMatrixBench(void* p) : INHERITED(p, "concat_floatfloat") {
103 init9(mya);
104 init9(myb);
105 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000106 }
107protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000108 virtual int mulLoopCount() const { return 4; }
109
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000110 static inline void muladdmul(float a, float b, float c, float d,
111 float* result) {
112 *result = a * b + c * d;
113 }
114 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000115 const float* a = mya;
116 const float* b = myb;
117 float* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000118 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
119 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
120 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000121 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000122 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
123 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
124 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000125 r[5] += a[5];
126 r[6] = r[7] = 0.0f;
127 r[8] = 1.0f;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000128 }
129private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000130 float mya [9];
131 float myb [9];
132 float myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000133 typedef MatrixBench INHERITED;
134};
135
136static inline float SkDoubleToFloat(double x) {
137 return static_cast<float>(x);
138}
139
140// Test the performance of setConcat() non-perspective case:
141// using floating point precision but casting up to float for
142// intermediate results during computations.
143class FloatDoubleConcatMatrixBench : public MatrixBench {
144public:
reed@google.come0dcde72011-06-06 13:20:29 +0000145 FloatDoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_floatdouble") {
146 init9(mya);
147 init9(myb);
148 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000149 }
150protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000151 virtual int mulLoopCount() const { return 4; }
152
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000153 static inline void muladdmul(float a, float b, float c, float d,
154 float* result) {
155 *result = SkDoubleToFloat((double)a * b + (double)c * d);
156 }
157 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000158 const float* a = mya;
159 const float* b = myb;
160 float* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000161 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
162 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
163 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000164 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000165 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
166 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
167 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000168 r[5] += a[5];
169 r[6] = r[7] = 0.0f;
170 r[8] = 1.0f;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000171 }
172private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000173 float mya [9];
174 float myb [9];
175 float myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000176 typedef MatrixBench INHERITED;
177};
178
179// Test the performance of setConcat() non-perspective case:
180// using double precision only.
181class DoubleConcatMatrixBench : public MatrixBench {
182public:
reed@google.come0dcde72011-06-06 13:20:29 +0000183 DoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_double") {
184 init9(mya);
185 init9(myb);
186 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000187 }
188protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000189 virtual int mulLoopCount() const { return 4; }
190
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000191 static inline void muladdmul(double a, double b, double c, double d,
192 double* result) {
193 *result = a * b + c * d;
194 }
195 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000196 const double* a = mya;
197 const double* b = myb;
198 double* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000199 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
200 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
201 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000202 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000203 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
204 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
205 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000206 r[5] += a[5];
207 r[6] = r[7] = 0.0;
208 r[8] = 1.0;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000209 }
210private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000211 double mya [9];
212 double myb [9];
213 double myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000214 typedef MatrixBench INHERITED;
215};
216
tomhudson@google.com288ff332011-06-07 14:31:38 +0000217#ifdef SK_SCALAR_IS_FLOAT
218class ScaleTransMixedMatrixBench : public MatrixBench {
219 public:
220 ScaleTransMixedMatrixBench(void* p) : INHERITED(p, "scaletrans_mixed"), fCount (16) {
221 fMatrix.setAll(fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
222 fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
223 fRandom.nextS(), fRandom.nextS(), fRandom.nextS());
224 int i;
225 for (i = 0; i < fCount; i++) {
226 fSrc[i].fX = fRandom.nextS();
227 fSrc[i].fY = fRandom.nextS();
228 fDst[i].fX = fRandom.nextS();
229 fDst[i].fY = fRandom.nextS();
230 }
231 }
232 protected:
233 virtual void performTest() {
234 SkPoint* dst = fDst;
235 const SkPoint* src = fSrc;
236 int count = fCount;
237 float mx = fMatrix[SkMatrix::kMScaleX];
238 float my = fMatrix[SkMatrix::kMScaleY];
239 float tx = fMatrix[SkMatrix::kMTransX];
240 float ty = fMatrix[SkMatrix::kMTransY];
241 do {
242 dst->fY = SkScalarMulAdd(src->fY, my, ty);
243 dst->fX = SkScalarMulAdd(src->fX, mx, tx);
244 src += 1;
245 dst += 1;
246 } while (--count);
247 }
248 private:
249 SkMatrix fMatrix;
250 SkPoint fSrc [16];
251 SkPoint fDst [16];
252 int fCount;
253 SkRandom fRandom;
254 typedef MatrixBench INHERITED;
255};
256
257
258class ScaleTransDoubleMatrixBench : public MatrixBench {
259 public:
260 ScaleTransDoubleMatrixBench(void* p) : INHERITED(p, "scaletrans_double"), fCount (16) {
261 init9(fMatrix);
262 int i;
263 for (i = 0; i < fCount; i++) {
264 fSrc[i].fX = fRandom.nextS();
265 fSrc[i].fY = fRandom.nextS();
266 fDst[i].fX = fRandom.nextS();
267 fDst[i].fY = fRandom.nextS();
268 }
269 }
270 protected:
271 virtual void performTest() {
272 SkPoint* dst = fDst;
273 const SkPoint* src = fSrc;
274 int count = fCount;
275 // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode
276 float mx = fMatrix[SkMatrix::kMScaleX];
277 float my = fMatrix[SkMatrix::kMScaleY];
278 float tx = fMatrix[SkMatrix::kMTransX];
279 float ty = fMatrix[SkMatrix::kMTransY];
280 do {
281 dst->fY = src->fY * my + ty;
282 dst->fX = src->fX * mx + tx;
283 src += 1;
284 dst += 1;
285 } while (--count);
286 }
287 private:
288 double fMatrix [9];
289 SkPoint fSrc [16];
290 SkPoint fDst [16];
291 int fCount;
292 SkRandom fRandom;
293 typedef MatrixBench INHERITED;
294};
295#endif
296
297
298
299
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000300
reed@google.com3fb51872011-06-01 15:11:22 +0000301static SkBenchmark* M0(void* p) { return new EqualsMatrixBench(p); }
302static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); }
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000303static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); }
304static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); }
305static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); }
reed@google.com3fb51872011-06-01 15:11:22 +0000306
307static BenchRegistry gReg0(M0);
308static BenchRegistry gReg1(M1);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000309static BenchRegistry gReg2(M2);
310static BenchRegistry gReg3(M3);
311static BenchRegistry gReg4(M4);
tomhudson@google.com288ff332011-06-07 14:31:38 +0000312
313#ifdef SK_SCALAR_IS_FLOAT
314static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); }
315static SkBenchmark* FlM1(void* p) { return new ScaleTransDoubleMatrixBench(p); }
316static BenchRegistry gFlReg5(FlM0);
317static BenchRegistry gFlReg6(FlM1);
318#endif