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 14class MatrixBench : public Benchmark { 15 SkString fName; 16public: 17 MatrixBench(const char name[]) { 18 fName.printf("matrix_%s", name); 19 } 20 21 bool isSuitableFor(Backend backend) override { 22 return backend == kNonRendering_Backend; 23 } 24 25 virtual void performTest() = 0; 26 27protected: 28 virtual int mulLoopCount() const { return 1; } 29 30 virtual const char* onGetName() { 31 return fName.c_str(); 32 } 33 34 virtual void onDraw(const int loops, SkCanvas*) { 35 for (int i = 0; i < loops; i++) { 36 this->performTest(); 37 } 38 } 39 40private: 41 typedef Benchmark INHERITED; 42}; 43 44 45class EqualsMatrixBench : public MatrixBench { 46public: 47 EqualsMatrixBench() : INHERITED("equals") {} 48protected: 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 } 62private: 63 typedef MatrixBench INHERITED; 64}; 65 66class ScaleMatrixBench : public MatrixBench { 67public: 68 ScaleMatrixBench() : INHERITED("scale") { 69 fSX = fSY = 1.5f; 70 fM0.reset(); 71 fM1.setScale(fSX, fSY); 72 fM2.setTranslate(fSX, fSY); 73 } 74protected: 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 } 81private: 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. 90template <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 97class GetTypeMatrixBench : public MatrixBench { 98public: 99 GetTypeMatrixBench() 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(); 110 } 111protected: 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()); 136 } 137private: 138 SkMatrix fMatrix; 139 float fArray[9]; 140 SkRandom fRnd; 141 typedef MatrixBench INHERITED; 142}; 143 144class DecomposeMatrixBench : public MatrixBench { 145public: 146 DecomposeMatrixBench() : INHERITED("decompose") {} 147 148protected: 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); 158 } 159 } 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); 164 } 165 } 166private: 167 SkMatrix fMatrix[10]; 168 SkRandom fRandom; 169 typedef MatrixBench INHERITED; 170}; 171 172class InvertMapRectMatrixBench : public MatrixBench { 173public: 174 InvertMapRectMatrixBench(const char* name, int flags) 175 : INHERITED(name) 176 , fFlags(flags) { 177 fMatrix.reset(); 178 fIteration = 0; 179 if (flags & kScale_Flag) { 180 fMatrix.postScale(1.5f, 2.5f); 181 } 182 if (flags & kTranslate_Flag) { 183 fMatrix.postTranslate(1.5f, 2.5f); 184 } 185 if (flags & kRotate_Flag) { 186 fMatrix.postRotate(45.0f); 187 } 188 if (flags & kPerspective_Flag) { 189 fMatrix.setPerspX(1.5f); 190 fMatrix.setPerspY(2.5f); 191 } 192 if (0 == (flags & kUncachedTypeMask_Flag)) { 193 fMatrix.getType(); 194 } 195 } 196 enum Flag { 197 kScale_Flag = 0x01, 198 kTranslate_Flag = 0x02, 199 kRotate_Flag = 0x04, 200 kPerspective_Flag = 0x08, 201 kUncachedTypeMask_Flag = 0x10, 202 }; 203protected: 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()); 209 } 210 SkMatrix inv; 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)); 216 if (invertible) { 217 inv.mapRect(&transformedRect, srcRect); 218 } 219 } 220private: 221 SkMatrix fMatrix; 222 int fFlags; 223 unsigned fIteration; 224 typedef MatrixBench INHERITED; 225}; 226 227/////////////////////////////////////////////////////////////////////////////// 228 229DEF_BENCH( return new EqualsMatrixBench(); ) 230DEF_BENCH( return new ScaleMatrixBench(); ) 231DEF_BENCH( return new GetTypeMatrixBench(); ) 232DEF_BENCH( return new DecomposeMatrixBench(); ) 233 234DEF_BENCH( return new InvertMapRectMatrixBench("invert_maprect_identity", 0); ) 235 236DEF_BENCH(return new InvertMapRectMatrixBench( 237 "invert_maprect_rectstaysrect", 238 InvertMapRectMatrixBench::kScale_Flag | 239 InvertMapRectMatrixBench::kTranslate_Flag); ) 240 241DEF_BENCH(return new InvertMapRectMatrixBench( 242 "invert_maprect_translate", 243 InvertMapRectMatrixBench::kTranslate_Flag); ) 244 245DEF_BENCH(return new InvertMapRectMatrixBench( 246 "invert_maprect_nonpersp", 247 InvertMapRectMatrixBench::kScale_Flag | 248 InvertMapRectMatrixBench::kRotate_Flag | 249 InvertMapRectMatrixBench::kTranslate_Flag); ) 250 251DEF_BENCH( return new InvertMapRectMatrixBench( 252 "invert_maprect_persp", 253 InvertMapRectMatrixBench::kPerspective_Flag); ) 254 255DEF_BENCH( return new InvertMapRectMatrixBench( 256 "invert_maprect_typemask_rectstaysrect", 257 InvertMapRectMatrixBench::kUncachedTypeMask_Flag | 258 InvertMapRectMatrixBench::kScale_Flag | 259 InvertMapRectMatrixBench::kTranslate_Flag); ) 260 261DEF_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); ) 267 268/////////////////////////////////////////////////////////////////////////////// 269 270static SkMatrix make_trans() { return SkMatrix::MakeTrans(2, 3); } 271static SkMatrix make_scale() { SkMatrix m(make_trans()); m.postScale(1.5f, 0.5f); return m; } 272static SkMatrix make_afine() { SkMatrix m(make_trans()); m.postRotate(15); return m; } 273 274class MapPointsMatrixBench : public MatrixBench { 275protected: 276 SkMatrix fM; 277 enum { 278 N = 32 279 }; 280 SkPoint fSrc[N], fDst[N]; 281public: 282 MapPointsMatrixBench(const char name[], const SkMatrix& m) 283 : MatrixBench(name), fM(m) 284 { 285 SkRandom rand; 286 for (int i = 0; i < N; ++i) { 287 fSrc[i].set(rand.nextSScalar1(), rand.nextSScalar1()); 288 } 289 } 290 291 void performTest() override { 292 for (int i = 0; i < 1000000; ++i) { 293 fM.mapPoints(fDst, fSrc, N); 294 } 295 } 296}; 297DEF_BENCH( return new MapPointsMatrixBench("mappoints_identity", SkMatrix::I()); ) 298DEF_BENCH( return new MapPointsMatrixBench("mappoints_trans", make_trans()); ) 299DEF_BENCH( return new MapPointsMatrixBench("mappoints_scale", make_scale()); ) 300DEF_BENCH( return new MapPointsMatrixBench("mappoints_affine", make_afine()); ) 301 302