blob: 88e1538676d3a4a001d708fd3a2ec482669ac192 [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") {
tomhudson@google.com7b4e1072011-06-03 19:16:56 +000070
reed@google.com3fb51872011-06-01 15:11:22 +000071 fM0.reset();
72 fM1.setScale(fSX, fSY);
73 fM2.setTranslate(fSX, fSY);
74 fSX = fSY = SkFloatToScalar(1.5f);
75 }
76protected:
77 virtual void performTest() {
78 SkMatrix m;
79 m = fM0; m.preScale(fSX, fSY);
80 m = fM1; m.preScale(fSX, fSY);
81 m = fM2; m.preScale(fSX, fSY);
82 }
83private:
84 SkMatrix fM0, fM1, fM2;
85 SkScalar fSX, fSY;
86 typedef MatrixBench INHERITED;
87};
88
reed@google.come0dcde72011-06-06 13:20:29 +000089// having unknown values in our arrays can throw off the timing a lot, perhaps
90// handling NaN values is a lot slower. Anyway, this guy is just meant to put
91// reasonable values in our arrays.
92template <typename T> void init9(T array[9]) {
93 SkRandom rand;
94 for (int i = 0; i < 9; i++) {
95 array[i] = rand.nextSScalar1();
96 }
97}
98
tomhudson@google.com7b4e1072011-06-03 19:16:56 +000099// Test the performance of setConcat() non-perspective case:
100// using floating point precision only.
101class FloatConcatMatrixBench : public MatrixBench {
102public:
reed@google.come0dcde72011-06-06 13:20:29 +0000103 FloatConcatMatrixBench(void* p) : INHERITED(p, "concat_floatfloat") {
104 init9(mya);
105 init9(myb);
106 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000107 }
108protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000109 virtual int mulLoopCount() const { return 4; }
110
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000111 static inline void muladdmul(float a, float b, float c, float d,
112 float* result) {
113 *result = a * b + c * d;
114 }
115 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000116 const float* a = mya;
117 const float* b = myb;
118 float* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000119 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
120 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
121 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000122 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000123 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
124 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
125 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000126 r[5] += a[5];
127 r[6] = r[7] = 0.0f;
128 r[8] = 1.0f;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000129 }
130private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000131 float mya [9];
132 float myb [9];
133 float myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000134 typedef MatrixBench INHERITED;
135};
136
137static inline float SkDoubleToFloat(double x) {
138 return static_cast<float>(x);
139}
140
141// Test the performance of setConcat() non-perspective case:
142// using floating point precision but casting up to float for
143// intermediate results during computations.
144class FloatDoubleConcatMatrixBench : public MatrixBench {
145public:
reed@google.come0dcde72011-06-06 13:20:29 +0000146 FloatDoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_floatdouble") {
147 init9(mya);
148 init9(myb);
149 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000150 }
151protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000152 virtual int mulLoopCount() const { return 4; }
153
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000154 static inline void muladdmul(float a, float b, float c, float d,
155 float* result) {
156 *result = SkDoubleToFloat((double)a * b + (double)c * d);
157 }
158 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000159 const float* a = mya;
160 const float* b = myb;
161 float* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000162 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
163 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
164 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000165 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000166 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
167 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
168 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000169 r[5] += a[5];
170 r[6] = r[7] = 0.0f;
171 r[8] = 1.0f;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000172 }
173private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000174 float mya [9];
175 float myb [9];
176 float myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000177 typedef MatrixBench INHERITED;
178};
179
180// Test the performance of setConcat() non-perspective case:
181// using double precision only.
182class DoubleConcatMatrixBench : public MatrixBench {
183public:
reed@google.come0dcde72011-06-06 13:20:29 +0000184 DoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_double") {
185 init9(mya);
186 init9(myb);
187 init9(myr);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000188 }
189protected:
reed@google.comcbefd7d2011-06-06 13:31:30 +0000190 virtual int mulLoopCount() const { return 4; }
191
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000192 static inline void muladdmul(double a, double b, double c, double d,
193 double* result) {
194 *result = a * b + c * d;
195 }
196 virtual void performTest() {
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000197 const double* a = mya;
198 const double* b = myb;
199 double* r = myr;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000200 muladdmul(a[0], b[0], a[1], b[3], &r[0]);
201 muladdmul(a[0], b[1], a[1], b[4], &r[1]);
202 muladdmul(a[0], b[2], a[1], b[5], &r[2]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000203 r[2] += a[2];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000204 muladdmul(a[3], b[0], a[4], b[3], &r[3]);
205 muladdmul(a[3], b[1], a[4], b[4], &r[4]);
206 muladdmul(a[3], b[2], a[4], b[5], &r[5]);
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000207 r[5] += a[5];
208 r[6] = r[7] = 0.0;
209 r[8] = 1.0;
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000210 }
211private:
tomhudson@google.coma20416b2011-06-03 20:32:58 +0000212 double mya [9];
213 double myb [9];
214 double myr [9];
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000215 typedef MatrixBench INHERITED;
216};
217
tomhudson@google.com288ff332011-06-07 14:31:38 +0000218#ifdef SK_SCALAR_IS_FLOAT
219class ScaleTransMixedMatrixBench : public MatrixBench {
220 public:
221 ScaleTransMixedMatrixBench(void* p) : INHERITED(p, "scaletrans_mixed"), fCount (16) {
222 fMatrix.setAll(fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
223 fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
224 fRandom.nextS(), fRandom.nextS(), fRandom.nextS());
225 int i;
226 for (i = 0; i < fCount; i++) {
227 fSrc[i].fX = fRandom.nextS();
228 fSrc[i].fY = fRandom.nextS();
229 fDst[i].fX = fRandom.nextS();
230 fDst[i].fY = fRandom.nextS();
231 }
232 }
233 protected:
234 virtual void performTest() {
235 SkPoint* dst = fDst;
236 const SkPoint* src = fSrc;
237 int count = fCount;
238 float mx = fMatrix[SkMatrix::kMScaleX];
239 float my = fMatrix[SkMatrix::kMScaleY];
240 float tx = fMatrix[SkMatrix::kMTransX];
241 float ty = fMatrix[SkMatrix::kMTransY];
242 do {
243 dst->fY = SkScalarMulAdd(src->fY, my, ty);
244 dst->fX = SkScalarMulAdd(src->fX, mx, tx);
245 src += 1;
246 dst += 1;
247 } while (--count);
248 }
249 private:
250 SkMatrix fMatrix;
251 SkPoint fSrc [16];
252 SkPoint fDst [16];
253 int fCount;
254 SkRandom fRandom;
255 typedef MatrixBench INHERITED;
256};
257
258
259class ScaleTransDoubleMatrixBench : public MatrixBench {
260 public:
261 ScaleTransDoubleMatrixBench(void* p) : INHERITED(p, "scaletrans_double"), fCount (16) {
262 init9(fMatrix);
263 int i;
264 for (i = 0; i < fCount; i++) {
265 fSrc[i].fX = fRandom.nextS();
266 fSrc[i].fY = fRandom.nextS();
267 fDst[i].fX = fRandom.nextS();
268 fDst[i].fY = fRandom.nextS();
269 }
270 }
271 protected:
272 virtual void performTest() {
273 SkPoint* dst = fDst;
274 const SkPoint* src = fSrc;
275 int count = fCount;
276 // As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode
277 float mx = fMatrix[SkMatrix::kMScaleX];
278 float my = fMatrix[SkMatrix::kMScaleY];
279 float tx = fMatrix[SkMatrix::kMTransX];
280 float ty = fMatrix[SkMatrix::kMTransY];
281 do {
282 dst->fY = src->fY * my + ty;
283 dst->fX = src->fX * mx + tx;
284 src += 1;
285 dst += 1;
286 } while (--count);
287 }
288 private:
289 double fMatrix [9];
290 SkPoint fSrc [16];
291 SkPoint fDst [16];
292 int fCount;
293 SkRandom fRandom;
294 typedef MatrixBench INHERITED;
295};
296#endif
297
298
299
300
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000301
reed@google.com3fb51872011-06-01 15:11:22 +0000302static SkBenchmark* M0(void* p) { return new EqualsMatrixBench(p); }
303static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); }
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000304static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); }
305static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); }
306static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); }
reed@google.com3fb51872011-06-01 15:11:22 +0000307
308static BenchRegistry gReg0(M0);
309static BenchRegistry gReg1(M1);
tomhudson@google.com7b4e1072011-06-03 19:16:56 +0000310static BenchRegistry gReg2(M2);
311static BenchRegistry gReg3(M3);
312static BenchRegistry gReg4(M4);
tomhudson@google.com288ff332011-06-07 14:31:38 +0000313
314#ifdef SK_SCALAR_IS_FLOAT
315static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); }
316static SkBenchmark* FlM1(void* p) { return new ScaleTransDoubleMatrixBench(p); }
317static BenchRegistry gFlReg5(FlM0);
318static BenchRegistry gFlReg6(FlM1);
319#endif