| /* | 
 |  * Copyright 2011 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 | #include "bench/Benchmark.h" | 
 | #include "include/core/SkMatrix.h" | 
 | #include "include/core/SkString.h" | 
 | #include "include/utils/SkRandom.h" | 
 | #include "src/core/SkMatrixUtils.h" | 
 |  | 
 | class MatrixBench : public Benchmark { | 
 |     SkString    fName; | 
 | public: | 
 |     MatrixBench(const char name[])  { | 
 |         fName.printf("matrix_%s", name); | 
 |     } | 
 |  | 
 |     bool isSuitableFor(Backend backend) override { | 
 |         return backend == kNonRendering_Backend; | 
 |     } | 
 |  | 
 |     virtual void performTest() = 0; | 
 |  | 
 | protected: | 
 |     virtual int mulLoopCount() const { return 1; } | 
 |  | 
 |     const char* onGetName() override { | 
 |         return fName.c_str(); | 
 |     } | 
 |  | 
 |     void onDraw(int loops, SkCanvas*) override { | 
 |         for (int i = 0; i < loops; i++) { | 
 |             this->performTest(); | 
 |         } | 
 |     } | 
 |  | 
 | private: | 
 |     typedef Benchmark INHERITED; | 
 | }; | 
 |  | 
 |  | 
 | class EqualsMatrixBench : public MatrixBench { | 
 | public: | 
 |     EqualsMatrixBench() : INHERITED("equals") {} | 
 | protected: | 
 |     void performTest() override { | 
 |         SkMatrix m0, m1, m2; | 
 |  | 
 |         m0.reset(); | 
 |         m1.reset(); | 
 |         m2.reset(); | 
 |  | 
 |         // xor into a volatile prevents these comparisons from being optimized away. | 
 |         volatile bool junk = false; | 
 |         junk ^= (m0 == m1); | 
 |         junk ^= (m1 == m2); | 
 |         junk ^= (m2 == m0); | 
 |     } | 
 | private: | 
 |     typedef MatrixBench INHERITED; | 
 | }; | 
 |  | 
 | class ScaleMatrixBench : public MatrixBench { | 
 | public: | 
 |     ScaleMatrixBench() : INHERITED("scale") { | 
 |         fSX = fSY = 1.5f; | 
 |         fM0.reset(); | 
 |         fM1.setScale(fSX, fSY); | 
 |         fM2.setTranslate(fSX, fSY); | 
 |     } | 
 | protected: | 
 |     void performTest() override { | 
 |         SkMatrix m; | 
 |         m = fM0; m.preScale(fSX, fSY); | 
 |         m = fM1; m.preScale(fSX, fSY); | 
 |         m = fM2; m.preScale(fSX, fSY); | 
 |     } | 
 | private: | 
 |     SkMatrix fM0, fM1, fM2; | 
 |     SkScalar fSX, fSY; | 
 |     typedef MatrixBench INHERITED; | 
 | }; | 
 |  | 
 | // having unknown values in our arrays can throw off the timing a lot, perhaps | 
 | // handling NaN values is a lot slower. Anyway, this guy is just meant to put | 
 | // reasonable values in our arrays. | 
 | template <typename T> void init9(T array[9]) { | 
 |     SkRandom rand; | 
 |     for (int i = 0; i < 9; i++) { | 
 |         array[i] = rand.nextSScalar1(); | 
 |     } | 
 | } | 
 |  | 
 | class GetTypeMatrixBench : public MatrixBench { | 
 | public: | 
 |     GetTypeMatrixBench() | 
 |         : INHERITED("gettype") { | 
 |         fArray[0] = (float) fRnd.nextS(); | 
 |         fArray[1] = (float) fRnd.nextS(); | 
 |         fArray[2] = (float) fRnd.nextS(); | 
 |         fArray[3] = (float) fRnd.nextS(); | 
 |         fArray[4] = (float) fRnd.nextS(); | 
 |         fArray[5] = (float) fRnd.nextS(); | 
 |         fArray[6] = (float) fRnd.nextS(); | 
 |         fArray[7] = (float) fRnd.nextS(); | 
 |         fArray[8] = (float) fRnd.nextS(); | 
 |     } | 
 | protected: | 
 |     // Putting random generation of the matrix inside performTest() | 
 |     // would help us avoid anomalous runs, but takes up 25% or | 
 |     // more of the function time. | 
 |     void performTest() override { | 
 |         fMatrix.setAll(fArray[0], fArray[1], fArray[2], | 
 |                        fArray[3], fArray[4], fArray[5], | 
 |                        fArray[6], fArray[7], fArray[8]); | 
 |         // xoring into a volatile prevents the compiler from optimizing these away | 
 |         volatile int junk = 0; | 
 |         junk ^= (fMatrix.getType()); | 
 |         fMatrix.dirtyMatrixTypeCache(); | 
 |         junk ^= (fMatrix.getType()); | 
 |         fMatrix.dirtyMatrixTypeCache(); | 
 |         junk ^= (fMatrix.getType()); | 
 |         fMatrix.dirtyMatrixTypeCache(); | 
 |         junk ^= (fMatrix.getType()); | 
 |         fMatrix.dirtyMatrixTypeCache(); | 
 |         junk ^= (fMatrix.getType()); | 
 |         fMatrix.dirtyMatrixTypeCache(); | 
 |         junk ^= (fMatrix.getType()); | 
 |         fMatrix.dirtyMatrixTypeCache(); | 
 |         junk ^= (fMatrix.getType()); | 
 |         fMatrix.dirtyMatrixTypeCache(); | 
 |         junk ^= (fMatrix.getType()); | 
 |     } | 
 | private: | 
 |     SkMatrix fMatrix; | 
 |     float fArray[9]; | 
 |     SkRandom fRnd; | 
 |     typedef MatrixBench INHERITED; | 
 | }; | 
 |  | 
 | class DecomposeMatrixBench : public MatrixBench { | 
 | public: | 
 |     DecomposeMatrixBench() : INHERITED("decompose") {} | 
 |  | 
 | protected: | 
 |     void onDelayedSetup() override { | 
 |         for (int i = 0; i < 10; ++i) { | 
 |             SkScalar rot0 = (fRandom.nextBool()) ? fRandom.nextRangeF(-180, 180) : 0.0f; | 
 |             SkScalar sx = fRandom.nextRangeF(-3000.f, 3000.f); | 
 |             SkScalar sy = (fRandom.nextBool()) ? fRandom.nextRangeF(-3000.f, 3000.f) : sx; | 
 |             SkScalar rot1 = fRandom.nextRangeF(-180, 180); | 
 |             fMatrix[i].setRotate(rot0); | 
 |             fMatrix[i].postScale(sx, sy); | 
 |             fMatrix[i].postRotate(rot1); | 
 |         } | 
 |     } | 
 |     void performTest() override { | 
 |         SkPoint rotation1, scale, rotation2; | 
 |         for (int i = 0; i < 10; ++i) { | 
 |             (void) SkDecomposeUpper2x2(fMatrix[i], &rotation1, &scale, &rotation2); | 
 |         } | 
 |     } | 
 | private: | 
 |     SkMatrix fMatrix[10]; | 
 |     SkRandom fRandom; | 
 |     typedef MatrixBench INHERITED; | 
 | }; | 
 |  | 
 | class InvertMapRectMatrixBench : public MatrixBench { | 
 | public: | 
 |     InvertMapRectMatrixBench(const char* name, int flags) | 
 |         : INHERITED(name) | 
 |         , fFlags(flags) { | 
 |         fMatrix.reset(); | 
 |         fIteration = 0; | 
 |         if (flags & kScale_Flag) { | 
 |             fMatrix.postScale(1.5f, 2.5f); | 
 |         } | 
 |         if (flags & kTranslate_Flag) { | 
 |             fMatrix.postTranslate(1.5f, 2.5f); | 
 |         } | 
 |         if (flags & kRotate_Flag) { | 
 |             fMatrix.postRotate(45.0f); | 
 |         } | 
 |         if (flags & kPerspective_Flag) { | 
 |             fMatrix.setPerspX(1.5f); | 
 |             fMatrix.setPerspY(2.5f); | 
 |         } | 
 |         if (0 == (flags & kUncachedTypeMask_Flag)) { | 
 |             fMatrix.getType(); | 
 |         } | 
 |     } | 
 |     enum Flag { | 
 |         kScale_Flag             = 0x01, | 
 |         kTranslate_Flag         = 0x02, | 
 |         kRotate_Flag            = 0x04, | 
 |         kPerspective_Flag       = 0x08, | 
 |         kUncachedTypeMask_Flag  = 0x10, | 
 |     }; | 
 | protected: | 
 |     void performTest() override { | 
 |         if (fFlags & kUncachedTypeMask_Flag) { | 
 |             // This will invalidate the typemask without | 
 |             // changing the matrix. | 
 |             fMatrix.setPerspX(fMatrix.getPerspX()); | 
 |         } | 
 |         SkMatrix inv; | 
 |         bool invertible = fMatrix.invert(&inv); | 
 |         SkASSERT(invertible); | 
 |         SkRect transformedRect; | 
 |         // an arbitrary, small, non-zero rect to transform | 
 |         SkRect srcRect = SkRect::MakeWH(SkIntToScalar(10), SkIntToScalar(10)); | 
 |         if (invertible) { | 
 |             inv.mapRect(&transformedRect, srcRect); | 
 |         } | 
 |     } | 
 | private: | 
 |     SkMatrix fMatrix; | 
 |     int fFlags; | 
 |     unsigned fIteration; | 
 |     typedef MatrixBench INHERITED; | 
 | }; | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | DEF_BENCH( return new EqualsMatrixBench(); ) | 
 | DEF_BENCH( return new ScaleMatrixBench(); ) | 
 | DEF_BENCH( return new GetTypeMatrixBench(); ) | 
 | DEF_BENCH( return new DecomposeMatrixBench(); ) | 
 |  | 
 | DEF_BENCH( return new InvertMapRectMatrixBench("invert_maprect_identity", 0); ) | 
 |  | 
 | DEF_BENCH(return new InvertMapRectMatrixBench( | 
 |                                   "invert_maprect_rectstaysrect", | 
 |                                   InvertMapRectMatrixBench::kScale_Flag | | 
 |                                   InvertMapRectMatrixBench::kTranslate_Flag); ) | 
 |  | 
 | DEF_BENCH(return new InvertMapRectMatrixBench( | 
 |                                   "invert_maprect_translate", | 
 |                                   InvertMapRectMatrixBench::kTranslate_Flag); ) | 
 |  | 
 | DEF_BENCH(return new InvertMapRectMatrixBench( | 
 |                                   "invert_maprect_nonpersp", | 
 |                                   InvertMapRectMatrixBench::kScale_Flag | | 
 |                                   InvertMapRectMatrixBench::kRotate_Flag | | 
 |                                   InvertMapRectMatrixBench::kTranslate_Flag); ) | 
 |  | 
 | DEF_BENCH( return new InvertMapRectMatrixBench( | 
 |                                "invert_maprect_persp", | 
 |                                InvertMapRectMatrixBench::kPerspective_Flag); ) | 
 |  | 
 | DEF_BENCH( return new InvertMapRectMatrixBench( | 
 |                            "invert_maprect_typemask_rectstaysrect", | 
 |                            InvertMapRectMatrixBench::kUncachedTypeMask_Flag | | 
 |                            InvertMapRectMatrixBench::kScale_Flag | | 
 |                            InvertMapRectMatrixBench::kTranslate_Flag); ) | 
 |  | 
 | DEF_BENCH( return new InvertMapRectMatrixBench( | 
 |                            "invert_maprect_typemask_nonpersp", | 
 |                            InvertMapRectMatrixBench::kUncachedTypeMask_Flag | | 
 |                            InvertMapRectMatrixBench::kScale_Flag | | 
 |                            InvertMapRectMatrixBench::kRotate_Flag | | 
 |                            InvertMapRectMatrixBench::kTranslate_Flag); ) | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | static SkMatrix make_trans() { return SkMatrix::Translate(2, 3); } | 
 | static SkMatrix make_scale() { SkMatrix m(make_trans()); m.postScale(1.5f, 0.5f); return m; } | 
 | static SkMatrix make_afine() { SkMatrix m(make_trans()); m.postRotate(15); return m; } | 
 |  | 
 | class MapPointsMatrixBench : public MatrixBench { | 
 | protected: | 
 |     SkMatrix fM; | 
 |     enum { | 
 |         N = 32 | 
 |     }; | 
 |     SkPoint fSrc[N], fDst[N]; | 
 | public: | 
 |     MapPointsMatrixBench(const char name[], const SkMatrix& m) | 
 |         : MatrixBench(name), fM(m) | 
 |     { | 
 |         SkRandom rand; | 
 |         for (int i = 0; i < N; ++i) { | 
 |             fSrc[i].set(rand.nextSScalar1(), rand.nextSScalar1()); | 
 |         } | 
 |     } | 
 |  | 
 |     void performTest() override { | 
 |         for (int i = 0; i < 1000000; ++i) { | 
 |             fM.mapPoints(fDst, fSrc, N); | 
 |         } | 
 |     } | 
 | }; | 
 | DEF_BENCH( return new MapPointsMatrixBench("mappoints_identity", SkMatrix::I()); ) | 
 | DEF_BENCH( return new MapPointsMatrixBench("mappoints_trans", make_trans()); ) | 
 | DEF_BENCH( return new MapPointsMatrixBench("mappoints_scale", make_scale()); ) | 
 | DEF_BENCH( return new MapPointsMatrixBench("mappoints_affine", make_afine()); ) | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | class MapRectMatrixBench : public MatrixBench { | 
 |     SkMatrix fM; | 
 |     SkRect   fR; | 
 |     bool     fScaleTrans; | 
 |  | 
 |     enum { MEGA_LOOP = 1000 * 1000 }; | 
 | public: | 
 |     MapRectMatrixBench(const char name[], bool scale_trans) | 
 |         : MatrixBench(name), fScaleTrans(scale_trans) | 
 |     { | 
 |         fM.setScale(2, 3); | 
 |         fM.postTranslate(1, 2); | 
 |  | 
 |         fR.setLTRB(10, 10, 100, 200); | 
 |     } | 
 |  | 
 |     void performTest() override { | 
 |         SkRect dst; | 
 |         if (fScaleTrans) { | 
 |             for (int i = 0; i < MEGA_LOOP; ++i) { | 
 |                 fM.mapRectScaleTranslate(&dst, fR); | 
 |             } | 
 |         } else { | 
 |             for (int i = 0; i < MEGA_LOOP; ++i) { | 
 |                 fM.mapRect(&dst, fR); | 
 |             } | 
 |         } | 
 |     } | 
 | }; | 
 | DEF_BENCH( return new MapRectMatrixBench("maprect", false); ) | 
 | DEF_BENCH( return new MapRectMatrixBench("maprectscaletrans", true); ) |