1 #include "SkBenchmark.h"
2 #include "SkMatrix.h"
3 #include "SkRandom.h"
4 #include "SkString.h"
5
6 class MatrixBench : public SkBenchmark {
7 SkString fName;
8 enum { N = 100000 };
9 public:
MatrixBench(void * param,const char name[])10 MatrixBench(void* param, const char name[]) : INHERITED(param) {
11 fName.printf("matrix_%s", name);
12 }
13
14 virtual void performTest() = 0;
15
16 protected:
mulLoopCount() const17 virtual int mulLoopCount() const { return 1; }
18
onGetName()19 virtual const char* onGetName() {
20 return fName.c_str();
21 }
22
onDraw(SkCanvas * canvas)23 virtual void onDraw(SkCanvas* canvas) {
24 int n = N * this->mulLoopCount();
25 for (int i = 0; i < n; i++) {
26 this->performTest();
27 }
28 }
29
30 private:
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
37 int gMatrixBench_NonStaticGlobal;
38
39 #define always_do(pred) \
40 do { \
41 if (pred) { \
42 ++gMatrixBench_NonStaticGlobal; \
43 } \
44 } while (0)
45
46 class EqualsMatrixBench : public MatrixBench {
47 public:
EqualsMatrixBench(void * param)48 EqualsMatrixBench(void* param) : INHERITED(param, "equals") {}
49 protected:
performTest()50 virtual void performTest() {
51 SkMatrix m0, m1, m2;
52
53 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 }
63 private:
64 typedef MatrixBench INHERITED;
65 };
66
67 class ScaleMatrixBench : public MatrixBench {
68 public:
ScaleMatrixBench(void * param)69 ScaleMatrixBench(void* param) : INHERITED(param, "scale") {
70 fSX = fSY = SkFloatToScalar(1.5f);
71 fM0.reset();
72 fM1.setScale(fSX, fSY);
73 fM2.setTranslate(fSX, fSY);
74 }
75 protected:
performTest()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 }
82 private:
83 SkMatrix fM0, fM1, fM2;
84 SkScalar fSX, fSY;
85 typedef MatrixBench INHERITED;
86 };
87
88 // 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.
init9(T array[9])91 template <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
98 // Test the performance of setConcat() non-perspective case:
99 // using floating point precision only.
100 class FloatConcatMatrixBench : public MatrixBench {
101 public:
FloatConcatMatrixBench(void * p)102 FloatConcatMatrixBench(void* p) : INHERITED(p, "concat_floatfloat") {
103 init9(mya);
104 init9(myb);
105 init9(myr);
106 }
107 protected:
mulLoopCount() const108 virtual int mulLoopCount() const { return 4; }
109
muladdmul(float a,float b,float c,float d,float * result)110 static inline void muladdmul(float a, float b, float c, float d,
111 float* result) {
112 *result = a * b + c * d;
113 }
performTest()114 virtual void performTest() {
115 const float* a = mya;
116 const float* b = myb;
117 float* r = myr;
118 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]);
121 r[2] += a[2];
122 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]);
125 r[5] += a[5];
126 r[6] = r[7] = 0.0f;
127 r[8] = 1.0f;
128 }
129 private:
130 float mya [9];
131 float myb [9];
132 float myr [9];
133 typedef MatrixBench INHERITED;
134 };
135
SkDoubleToFloat(double x)136 static 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.
143 class FloatDoubleConcatMatrixBench : public MatrixBench {
144 public:
FloatDoubleConcatMatrixBench(void * p)145 FloatDoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_floatdouble") {
146 init9(mya);
147 init9(myb);
148 init9(myr);
149 }
150 protected:
mulLoopCount() const151 virtual int mulLoopCount() const { return 4; }
152
muladdmul(float a,float b,float c,float d,float * result)153 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 }
performTest()157 virtual void performTest() {
158 const float* a = mya;
159 const float* b = myb;
160 float* r = myr;
161 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]);
164 r[2] += a[2];
165 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]);
168 r[5] += a[5];
169 r[6] = r[7] = 0.0f;
170 r[8] = 1.0f;
171 }
172 private:
173 float mya [9];
174 float myb [9];
175 float myr [9];
176 typedef MatrixBench INHERITED;
177 };
178
179 // Test the performance of setConcat() non-perspective case:
180 // using double precision only.
181 class DoubleConcatMatrixBench : public MatrixBench {
182 public:
DoubleConcatMatrixBench(void * p)183 DoubleConcatMatrixBench(void* p) : INHERITED(p, "concat_double") {
184 init9(mya);
185 init9(myb);
186 init9(myr);
187 }
188 protected:
mulLoopCount() const189 virtual int mulLoopCount() const { return 4; }
190
muladdmul(double a,double b,double c,double d,double * result)191 static inline void muladdmul(double a, double b, double c, double d,
192 double* result) {
193 *result = a * b + c * d;
194 }
performTest()195 virtual void performTest() {
196 const double* a = mya;
197 const double* b = myb;
198 double* r = myr;
199 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]);
202 r[2] += a[2];
203 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]);
206 r[5] += a[5];
207 r[6] = r[7] = 0.0;
208 r[8] = 1.0;
209 }
210 private:
211 double mya [9];
212 double myb [9];
213 double myr [9];
214 typedef MatrixBench INHERITED;
215 };
216
217 #ifdef SK_SCALAR_IS_FLOAT
218 class ScaleTransMixedMatrixBench : public MatrixBench {
219 public:
ScaleTransMixedMatrixBench(void * p)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:
performTest()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
258 class ScaleTransDoubleMatrixBench : public MatrixBench {
259 public:
ScaleTransDoubleMatrixBench(void * p)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:
performTest()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
300
M0(void * p)301 static SkBenchmark* M0(void* p) { return new EqualsMatrixBench(p); }
M1(void * p)302 static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); }
M2(void * p)303 static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); }
M3(void * p)304 static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); }
M4(void * p)305 static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); }
306
307 static BenchRegistry gReg0(M0);
308 static BenchRegistry gReg1(M1);
309 static BenchRegistry gReg2(M2);
310 static BenchRegistry gReg3(M3);
311 static BenchRegistry gReg4(M4);
312
313 #ifdef SK_SCALAR_IS_FLOAT
FlM0(void * p)314 static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); }
FlM1(void * p)315 static SkBenchmark* FlM1(void* p) { return new ScaleTransDoubleMatrixBench(p); }
316 static BenchRegistry gFlReg5(FlM0);
317 static BenchRegistry gFlReg6(FlM1);
318 #endif
319