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