3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
10 #include "SkMatrixUtils.h"
14 class MatrixBench : public Benchmark {
17 MatrixBench(const char name[]) {
18 fName.printf("matrix_%s", name);
21 bool isSuitableFor(Backend backend) SK_OVERRIDE {
22 return backend == kNonRendering_Backend;
25 virtual void performTest() = 0;
28 virtual int mulLoopCount() const { return 1; }
30 virtual const char* onGetName() {
34 virtual void onDraw(const int loops, SkCanvas*) {
35 for (int i = 0; i < loops; i++) {
41 typedef Benchmark INHERITED;
45 class EqualsMatrixBench : public MatrixBench {
47 EqualsMatrixBench() : INHERITED("equals") {}
49 virtual void performTest() {
56 // xor into a volatile prevents these comparisons from being optimized away.
57 volatile bool junk = false;
63 typedef MatrixBench INHERITED;
66 class ScaleMatrixBench : public MatrixBench {
68 ScaleMatrixBench() : INHERITED("scale") {
71 fM1.setScale(fSX, fSY);
72 fM2.setTranslate(fSX, fSY);
75 virtual void performTest() {
77 m = fM0; m.preScale(fSX, fSY);
78 m = fM1; m.preScale(fSX, fSY);
79 m = fM2; m.preScale(fSX, fSY);
82 SkMatrix fM0, fM1, fM2;
84 typedef MatrixBench INHERITED;
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.
90 template <typename T> void init9(T array[9]) {
92 for (int i = 0; i < 9; i++) {
93 array[i] = rand.nextSScalar1();
97 class GetTypeMatrixBench : public MatrixBench {
100 : INHERITED("gettype") {
101 fArray[0] = (float) fRnd.nextS();
102 fArray[1] = (float) fRnd.nextS();
103 fArray[2] = (float) fRnd.nextS();
104 fArray[3] = (float) fRnd.nextS();
105 fArray[4] = (float) fRnd.nextS();
106 fArray[5] = (float) fRnd.nextS();
107 fArray[6] = (float) fRnd.nextS();
108 fArray[7] = (float) fRnd.nextS();
109 fArray[8] = (float) fRnd.nextS();
112 // Putting random generation of the matrix inside performTest()
113 // would help us avoid anomalous runs, but takes up 25% or
114 // more of the function time.
115 virtual void performTest() {
116 fMatrix.setAll(fArray[0], fArray[1], fArray[2],
117 fArray[3], fArray[4], fArray[5],
118 fArray[6], fArray[7], fArray[8]);
119 // xoring into a volatile prevents the compiler from optimizing these away
120 volatile int junk = 0;
121 junk ^= (fMatrix.getType());
122 fMatrix.dirtyMatrixTypeCache();
123 junk ^= (fMatrix.getType());
124 fMatrix.dirtyMatrixTypeCache();
125 junk ^= (fMatrix.getType());
126 fMatrix.dirtyMatrixTypeCache();
127 junk ^= (fMatrix.getType());
128 fMatrix.dirtyMatrixTypeCache();
129 junk ^= (fMatrix.getType());
130 fMatrix.dirtyMatrixTypeCache();
131 junk ^= (fMatrix.getType());
132 fMatrix.dirtyMatrixTypeCache();
133 junk ^= (fMatrix.getType());
134 fMatrix.dirtyMatrixTypeCache();
135 junk ^= (fMatrix.getType());
141 typedef MatrixBench INHERITED;
144 class DecomposeMatrixBench : public MatrixBench {
146 DecomposeMatrixBench() : INHERITED("decompose") {}
149 virtual void onPreDraw() {
150 for (int i = 0; i < 10; ++i) {
151 SkScalar rot0 = (fRandom.nextBool()) ? fRandom.nextRangeF(-180, 180) : 0.0f;
152 SkScalar sx = fRandom.nextRangeF(-3000.f, 3000.f);
153 SkScalar sy = (fRandom.nextBool()) ? fRandom.nextRangeF(-3000.f, 3000.f) : sx;
154 SkScalar rot1 = fRandom.nextRangeF(-180, 180);
155 fMatrix[i].setRotate(rot0);
156 fMatrix[i].postScale(sx, sy);
157 fMatrix[i].postRotate(rot1);
160 virtual void performTest() {
161 SkPoint rotation1, scale, rotation2;
162 for (int i = 0; i < 10; ++i) {
163 (void) SkDecomposeUpper2x2(fMatrix[i], &rotation1, &scale, &rotation2);
167 SkMatrix fMatrix[10];
169 typedef MatrixBench INHERITED;
172 class InvertMapRectMatrixBench : public MatrixBench {
174 InvertMapRectMatrixBench(const char* name, int flags)
179 if (flags & kScale_Flag) {
180 fMatrix.postScale(1.5f, 2.5f);
182 if (flags & kTranslate_Flag) {
183 fMatrix.postTranslate(1.5f, 2.5f);
185 if (flags & kRotate_Flag) {
186 fMatrix.postRotate(45.0f);
188 if (flags & kPerspective_Flag) {
189 fMatrix.setPerspX(1.5f);
190 fMatrix.setPerspY(2.5f);
192 if (0 == (flags & kUncachedTypeMask_Flag)) {
198 kTranslate_Flag = 0x02,
200 kPerspective_Flag = 0x08,
201 kUncachedTypeMask_Flag = 0x10,
204 virtual void performTest() {
205 if (fFlags & kUncachedTypeMask_Flag) {
206 // This will invalidate the typemask without
207 // changing the matrix.
208 fMatrix.setPerspX(fMatrix.getPerspX());
211 bool invertible = fMatrix.invert(&inv);
212 SkASSERT(invertible);
213 SkRect transformedRect;
214 // an arbitrary, small, non-zero rect to transform
215 SkRect srcRect = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10));
217 inv.mapRect(&transformedRect, srcRect);
224 typedef MatrixBench INHERITED;
227 ///////////////////////////////////////////////////////////////////////////////
229 DEF_BENCH( return new EqualsMatrixBench(); )
230 DEF_BENCH( return new ScaleMatrixBench(); )
231 DEF_BENCH( return new GetTypeMatrixBench(); )
232 DEF_BENCH( return new DecomposeMatrixBench(); )
234 DEF_BENCH( return new InvertMapRectMatrixBench("invert_maprect_identity", 0); )
236 DEF_BENCH(return new InvertMapRectMatrixBench(
237 "invert_maprect_rectstaysrect",
238 InvertMapRectMatrixBench::kScale_Flag |
239 InvertMapRectMatrixBench::kTranslate_Flag); )
241 DEF_BENCH(return new InvertMapRectMatrixBench(
242 "invert_maprect_translate",
243 InvertMapRectMatrixBench::kTranslate_Flag); )
245 DEF_BENCH(return new InvertMapRectMatrixBench(
246 "invert_maprect_nonpersp",
247 InvertMapRectMatrixBench::kScale_Flag |
248 InvertMapRectMatrixBench::kRotate_Flag |
249 InvertMapRectMatrixBench::kTranslate_Flag); )
251 DEF_BENCH( return new InvertMapRectMatrixBench(
252 "invert_maprect_persp",
253 InvertMapRectMatrixBench::kPerspective_Flag); )
255 DEF_BENCH( return new InvertMapRectMatrixBench(
256 "invert_maprect_typemask_rectstaysrect",
257 InvertMapRectMatrixBench::kUncachedTypeMask_Flag |
258 InvertMapRectMatrixBench::kScale_Flag |
259 InvertMapRectMatrixBench::kTranslate_Flag); )
261 DEF_BENCH( return new InvertMapRectMatrixBench(
262 "invert_maprect_typemask_nonpersp",
263 InvertMapRectMatrixBench::kUncachedTypeMask_Flag |
264 InvertMapRectMatrixBench::kScale_Flag |
265 InvertMapRectMatrixBench::kRotate_Flag |
266 InvertMapRectMatrixBench::kTranslate_Flag); )
268 ///////////////////////////////////////////////////////////////////////////////
270 static SkMatrix make_ident() { SkMatrix m; m.reset(); return m; }
271 static SkMatrix make_trans() { SkMatrix m; m.setTranslate(2, 3); return m; }
272 static SkMatrix make_scale() { SkMatrix m(make_trans()); m.postScale(1.5f, 0.5f); return m; }
273 static SkMatrix make_afine() { SkMatrix m(make_trans()); m.postRotate(15); return m; }
275 class MapPointsMatrixBench : public MatrixBench {
281 SkPoint fSrc[N], fDst[N];
284 MapPointsMatrixBench(const char name[], const SkMatrix& m, bool newWay)
285 : MatrixBench(name), fM(m), fNewWay(newWay)
288 for (int i = 0; i < N; ++i) {
289 fSrc[i].set(rand.nextSScalar1(), rand.nextSScalar1());
293 void performTest() SK_OVERRIDE {
295 for (int i = 0; i < 1000000; ++i) {
296 fM.mapPts(fDst, fSrc, N);
299 for (int i = 0; i < 1000000; ++i) {
300 fM.mapPoints(fDst, fSrc, N);
305 DEF_BENCH( return new MapPointsMatrixBench("mappts_ident0", make_ident(), false); )
306 DEF_BENCH( return new MapPointsMatrixBench("mappts_ident1", make_ident(), true); )
307 DEF_BENCH( return new MapPointsMatrixBench("mappts_trans0", make_trans(), false); )
308 DEF_BENCH( return new MapPointsMatrixBench("mappts_trans1", make_trans(), true); )
309 DEF_BENCH( return new MapPointsMatrixBench("mappts_scale0", make_scale(), false); )
310 DEF_BENCH( return new MapPointsMatrixBench("mappts_scale1", make_scale(), true); )
311 DEF_BENCH( return new MapPointsMatrixBench("mappts_afine0", make_afine(), false); )
312 DEF_BENCH( return new MapPointsMatrixBench("mappts_afine1", make_afine(), true); )