1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 #include "Benchmark.h" 8 #include "SkMatrix.h" 9 #include "SkMatrixUtils.h" 10 #include "SkRandom.h" 11 #include "SkString.h" 12 13 class MatrixBench : public Benchmark { 14 SkString fName; 15 public: 16 MatrixBench(const char name[]) { 17 fName.printf("matrix_%s", name); 18 } 19 20 bool isSuitableFor(Backend backend) override { 21 return backend == kNonRendering_Backend; 22 } 23 24 virtual void performTest() = 0; 25 26 protected: 27 virtual int mulLoopCount() const { return 1; } 28 29 const char* onGetName() override { 30 return fName.c_str(); 31 } 32 33 void onDraw(int loops, SkCanvas*) override { 34 for (int i = 0; i < loops; i++) { 35 this->performTest(); 36 } 37 } 38 39 private: 40 typedef Benchmark INHERITED; 41 }; 42 43 44 class EqualsMatrixBench : public MatrixBench { 45 public: 46 EqualsMatrixBench() : INHERITED("equals") {} 47 protected: 48 void performTest() override { 49 SkMatrix m0, m1, m2; 50 51 m0.reset(); 52 m1.reset(); 53 m2.reset(); 54 55 // xor into a volatile prevents these comparisons from being optimized away. 56 volatile bool junk = false; 57 junk ^= (m0 == m1); 58 junk ^= (m1 == m2); 59 junk ^= (m2 == m0); 60 } 61 private: 62 typedef MatrixBench INHERITED; 63 }; 64 65 class ScaleMatrixBench : public MatrixBench { 66 public: 67 ScaleMatrixBench() : INHERITED("scale") { 68 fSX = fSY = 1.5f; 69 fM0.reset(); 70 fM1.setScale(fSX, fSY); 71 fM2.setTranslate(fSX, fSY); 72 } 73 protected: 74 void performTest() override { 75 SkMatrix m; 76 m = fM0; m.preScale(fSX, fSY); 77 m = fM1; m.preScale(fSX, fSY); 78 m = fM2; m.preScale(fSX, fSY); 79 } 80 private: 81 SkMatrix fM0, fM1, fM2; 82 SkScalar fSX, fSY; 83 typedef MatrixBench INHERITED; 84 }; 85 86 // having unknown values in our arrays can throw off the timing a lot, perhaps 87 // handling NaN values is a lot slower. Anyway, this guy is just meant to put 88 // reasonable values in our arrays. 89 template <typename T> void init9(T array[9]) { 90 SkRandom rand; 91 for (int i = 0; i < 9; i++) { 92 array[i] = rand.nextSScalar1(); 93 } 94 } 95 96 class GetTypeMatrixBench : public MatrixBench { 97 public: 98 GetTypeMatrixBench() 99 : INHERITED("gettype") { 100 fArray[0] = (float) fRnd.nextS(); 101 fArray[1] = (float) fRnd.nextS(); 102 fArray[2] = (float) fRnd.nextS(); 103 fArray[3] = (float) fRnd.nextS(); 104 fArray[4] = (float) fRnd.nextS(); 105 fArray[5] = (float) fRnd.nextS(); 106 fArray[6] = (float) fRnd.nextS(); 107 fArray[7] = (float) fRnd.nextS(); 108 fArray[8] = (float) fRnd.nextS(); 109 } 110 protected: 111 // Putting random generation of the matrix inside performTest() 112 // would help us avoid anomalous runs, but takes up 25% or 113 // more of the function time. 114 void performTest() override { 115 fMatrix.setAll(fArray[0], fArray[1], fArray[2], 116 fArray[3], fArray[4], fArray[5], 117 fArray[6], fArray[7], fArray[8]); 118 // xoring into a volatile prevents the compiler from optimizing these away 119 volatile int junk = 0; 120 junk ^= (fMatrix.getType()); 121 fMatrix.dirtyMatrixTypeCache(); 122 junk ^= (fMatrix.getType()); 123 fMatrix.dirtyMatrixTypeCache(); 124 junk ^= (fMatrix.getType()); 125 fMatrix.dirtyMatrixTypeCache(); 126 junk ^= (fMatrix.getType()); 127 fMatrix.dirtyMatrixTypeCache(); 128 junk ^= (fMatrix.getType()); 129 fMatrix.dirtyMatrixTypeCache(); 130 junk ^= (fMatrix.getType()); 131 fMatrix.dirtyMatrixTypeCache(); 132 junk ^= (fMatrix.getType()); 133 fMatrix.dirtyMatrixTypeCache(); 134 junk ^= (fMatrix.getType()); 135 } 136 private: 137 SkMatrix fMatrix; 138 float fArray[9]; 139 SkRandom fRnd; 140 typedef MatrixBench INHERITED; 141 }; 142 143 class DecomposeMatrixBench : public MatrixBench { 144 public: 145 DecomposeMatrixBench() : INHERITED("decompose") {} 146 147 protected: 148 void onDelayedSetup() override { 149 for (int i = 0; i < 10; ++i) { 150 SkScalar rot0 = (fRandom.nextBool()) ? fRandom.nextRangeF(-180, 180) : 0.0f; 151 SkScalar sx = fRandom.nextRangeF(-3000.f, 3000.f); 152 SkScalar sy = (fRandom.nextBool()) ? fRandom.nextRangeF(-3000.f, 3000.f) : sx; 153 SkScalar rot1 = fRandom.nextRangeF(-180, 180); 154 fMatrix[i].setRotate(rot0); 155 fMatrix[i].postScale(sx, sy); 156 fMatrix[i].postRotate(rot1); 157 } 158 } 159 void performTest() override { 160 SkPoint rotation1, scale, rotation2; 161 for (int i = 0; i < 10; ++i) { 162 (void) SkDecomposeUpper2x2(fMatrix[i], &rotation1, &scale, &rotation2); 163 } 164 } 165 private: 166 SkMatrix fMatrix[10]; 167 SkRandom fRandom; 168 typedef MatrixBench INHERITED; 169 }; 170 171 class InvertMapRectMatrixBench : public MatrixBench { 172 public: 173 InvertMapRectMatrixBench(const char* name, int flags) 174 : INHERITED(name) 175 , fFlags(flags) { 176 fMatrix.reset(); 177 fIteration = 0; 178 if (flags & kScale_Flag) { 179 fMatrix.postScale(1.5f, 2.5f); 180 } 181 if (flags & kTranslate_Flag) { 182 fMatrix.postTranslate(1.5f, 2.5f); 183 } 184 if (flags & kRotate_Flag) { 185 fMatrix.postRotate(45.0f); 186 } 187 if (flags & kPerspective_Flag) { 188 fMatrix.setPerspX(1.5f); 189 fMatrix.setPerspY(2.5f); 190 } 191 if (0 == (flags & kUncachedTypeMask_Flag)) { 192 fMatrix.getType(); 193 } 194 } 195 enum Flag { 196 kScale_Flag = 0x01, 197 kTranslate_Flag = 0x02, 198 kRotate_Flag = 0x04, 199 kPerspective_Flag = 0x08, 200 kUncachedTypeMask_Flag = 0x10, 201 }; 202 protected: 203 void performTest() override { 204 if (fFlags & kUncachedTypeMask_Flag) { 205 // This will invalidate the typemask without 206 // changing the matrix. 207 fMatrix.setPerspX(fMatrix.getPerspX()); 208 } 209 SkMatrix inv; 210 bool invertible = fMatrix.invert(&inv); 211 SkASSERT(invertible); 212 SkRect transformedRect; 213 // an arbitrary, small, non-zero rect to transform 214 SkRect srcRect = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10)); 215 if (invertible) { 216 inv.mapRect(&transformedRect, srcRect); 217 } 218 } 219 private: 220 SkMatrix fMatrix; 221 int fFlags; 222 unsigned fIteration; 223 typedef MatrixBench INHERITED; 224 }; 225 226 /////////////////////////////////////////////////////////////////////////////// 227 228 DEF_BENCH( return new EqualsMatrixBench(); ) 229 DEF_BENCH( return new ScaleMatrixBench(); ) 230 DEF_BENCH( return new GetTypeMatrixBench(); ) 231 DEF_BENCH( return new DecomposeMatrixBench(); ) 232 233 DEF_BENCH( return new InvertMapRectMatrixBench("invert_maprect_identity", 0); ) 234 235 DEF_BENCH(return new InvertMapRectMatrixBench( 236 "invert_maprect_rectstaysrect", 237 InvertMapRectMatrixBench::kScale_Flag | 238 InvertMapRectMatrixBench::kTranslate_Flag); ) 239 240 DEF_BENCH(return new InvertMapRectMatrixBench( 241 "invert_maprect_translate", 242 InvertMapRectMatrixBench::kTranslate_Flag); ) 243 244 DEF_BENCH(return new InvertMapRectMatrixBench( 245 "invert_maprect_nonpersp", 246 InvertMapRectMatrixBench::kScale_Flag | 247 InvertMapRectMatrixBench::kRotate_Flag | 248 InvertMapRectMatrixBench::kTranslate_Flag); ) 249 250 DEF_BENCH( return new InvertMapRectMatrixBench( 251 "invert_maprect_persp", 252 InvertMapRectMatrixBench::kPerspective_Flag); ) 253 254 DEF_BENCH( return new InvertMapRectMatrixBench( 255 "invert_maprect_typemask_rectstaysrect", 256 InvertMapRectMatrixBench::kUncachedTypeMask_Flag | 257 InvertMapRectMatrixBench::kScale_Flag | 258 InvertMapRectMatrixBench::kTranslate_Flag); ) 259 260 DEF_BENCH( return new InvertMapRectMatrixBench( 261 "invert_maprect_typemask_nonpersp", 262 InvertMapRectMatrixBench::kUncachedTypeMask_Flag | 263 InvertMapRectMatrixBench::kScale_Flag | 264 InvertMapRectMatrixBench::kRotate_Flag | 265 InvertMapRectMatrixBench::kTranslate_Flag); ) 266 267 /////////////////////////////////////////////////////////////////////////////// 268 269 static SkMatrix make_trans() { return SkMatrix::MakeTrans(2, 3); } 270 static SkMatrix make_scale() { SkMatrix m(make_trans()); m.postScale(1.5f, 0.5f); return m; } 271 static SkMatrix make_afine() { SkMatrix m(make_trans()); m.postRotate(15); return m; } 272 273 class MapPointsMatrixBench : public MatrixBench { 274 protected: 275 SkMatrix fM; 276 enum { 277 N = 32 278 }; 279 SkPoint fSrc[N], fDst[N]; 280 public: 281 MapPointsMatrixBench(const char name[], const SkMatrix& m) 282 : MatrixBench(name), fM(m) 283 { 284 SkRandom rand; 285 for (int i = 0; i < N; ++i) { 286 fSrc[i].set(rand.nextSScalar1(), rand.nextSScalar1()); 287 } 288 } 289 290 void performTest() override { 291 for (int i = 0; i < 1000000; ++i) { 292 fM.mapPoints(fDst, fSrc, N); 293 } 294 } 295 }; 296 DEF_BENCH( return new MapPointsMatrixBench("mappoints_identity", SkMatrix::I()); ) 297 DEF_BENCH( return new MapPointsMatrixBench("mappoints_trans", make_trans()); ) 298 DEF_BENCH( return new MapPointsMatrixBench("mappoints_scale", make_scale()); ) 299 DEF_BENCH( return new MapPointsMatrixBench("mappoints_affine", make_afine()); ) 300 301 /////////////////////////////////////////////////////////////////////////////// 302 303 class MapRectMatrixBench : public MatrixBench { 304 SkMatrix fM; 305 SkRect fR; 306 bool fScaleTrans; 307 308 enum { MEGA_LOOP = 1000 * 1000 }; 309 public: 310 MapRectMatrixBench(const char name[], bool scale_trans) 311 : MatrixBench(name), fScaleTrans(scale_trans) 312 { 313 fM.setScale(2, 3); 314 fM.postTranslate(1, 2); 315 316 fR.set(10, 10, 100, 200); 317 } 318 319 void performTest() override { 320 SkRect dst; 321 if (fScaleTrans) { 322 for (int i = 0; i < MEGA_LOOP; ++i) { 323 fM.mapRectScaleTranslate(&dst, fR); 324 } 325 } else { 326 for (int i = 0; i < MEGA_LOOP; ++i) { 327 fM.mapRect(&dst, fR); 328 } 329 } 330 } 331 }; 332 DEF_BENCH( return new MapRectMatrixBench("maprect", false); ) 333 DEF_BENCH( return new MapRectMatrixBench("maprectscaletrans", true); ) 334