MatrixBench.cpp 11 KB

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