• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 
8 #include "bench/Benchmark.h"
9 #include "include/core/SkRect.h"
10 #include "include/private/SkTemplates.h"
11 #include "src/utils/SkPolyUtils.h"
12 
13 class PolyUtilsBench : public Benchmark {
14 public:
15     // Evaluate SkTriangulateSimplePolygon's performance (via derived classes) on:
16     //   a non-self-intersecting star, a circle of tiny line segments and a self-intersecting star
17     enum class Type { kConvexCheck, kSimpleCheck, kInsetConvex, kOffsetSimple, kTessellateSimple };
18 
PolyUtilsBench(Type type)19     PolyUtilsBench(Type type) : fType(type) {}
20 
21     virtual void appendName(SkString*) = 0;
22     virtual void makePoly(SkTDArray<SkPoint>* poly) = 0;
complexity()23     virtual int complexity() { return 0; }
24 
25 protected:
onGetName()26     const char* onGetName() override {
27         fName = "poly_utils_";
28         this->appendName(&fName);
29         switch (fType) {
30         case Type::kConvexCheck:
31             fName.append("_c");
32             break;
33         case Type::kSimpleCheck:
34             fName.append("_s");
35             break;
36         case Type::kInsetConvex:
37             fName.append("_i");
38             break;
39         case Type::kOffsetSimple:
40             fName.append("_o");
41             break;
42         case Type::kTessellateSimple:
43             fName.append("_t");
44             break;
45         }
46         return fName.c_str();
47     }
48 
onDraw(int loops,SkCanvas * canvas)49     void onDraw(int loops, SkCanvas* canvas) override {
50         SkTDArray<SkPoint> poly;
51         this->makePoly(&poly);
52         switch (fType) {
53             case Type::kConvexCheck:
54                 for (int i = 0; i < loops; i++) {
55                     (void)SkIsConvexPolygon(poly.begin(), poly.count());
56                 }
57                 break;
58             case Type::kSimpleCheck:
59                 for (int i = 0; i < loops; i++) {
60                     (void)SkIsSimplePolygon(poly.begin(), poly.count());
61                 }
62                 break;
63             case Type::kInsetConvex:
64                 if (SkIsConvexPolygon(poly.begin(), poly.count())) {
65                     SkTDArray<SkPoint> result;
66                     for (int i = 0; i < loops; i++) {
67                         (void)SkInsetConvexPolygon(poly.begin(), poly.count(), 10, &result);
68                         (void)SkInsetConvexPolygon(poly.begin(), poly.count(), 40, &result);
69                     }
70                 }
71                 break;
72             case Type::kOffsetSimple:
73                 if (SkIsSimplePolygon(poly.begin(), poly.count())) {
74                     SkTDArray<SkPoint> result;
75                     SkRect bounds;
76                     bounds.setBounds(poly.begin(), poly.count());
77                     for (int i = 0; i < loops; i++) {
78                         (void)SkOffsetSimplePolygon(poly.begin(), poly.count(), bounds, 10,
79                                                     &result);
80                         (void)SkOffsetSimplePolygon(poly.begin(), poly.count(), bounds, -10,
81                                                     &result);
82                     }
83                 }
84                 break;
85             case Type::kTessellateSimple:
86                 if (SkIsSimplePolygon(poly.begin(), poly.count())) {
87                     SkAutoSTMalloc<64, uint16_t> indexMap(poly.count());
88                     for (int i = 0; i < poly.count(); ++i) {
89                         indexMap[i] = i;
90                     }
91                     SkTDArray<uint16_t> triangleIndices;
92                     for (int i = 0; i < loops; i++) {
93                         SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
94                                                    &triangleIndices);
95                     }
96                 }
97                 break;
98         }
99     }
100 
101 private:
102     SkString           fName;
103     Type               fType;
104 
105     using INHERITED = Benchmark;
106 };
107 
108 class StarPolyUtilsBench : public PolyUtilsBench {
109 public:
StarPolyUtilsBench(PolyUtilsBench::Type type)110     StarPolyUtilsBench(PolyUtilsBench::Type type) : INHERITED(type) {}
111 
appendName(SkString * name)112     void appendName(SkString* name) override {
113         name->append("star");
114     }
makePoly(SkTDArray<SkPoint> * poly)115     void makePoly(SkTDArray<SkPoint>* poly) override {
116         // create non-intersecting star
117         const SkScalar c = SkIntToScalar(45);
118         const SkScalar r1 = SkIntToScalar(20);
119         const SkScalar r2 = SkIntToScalar(3);
120         const int n = 500;
121         SkScalar rad = 0;
122         const SkScalar drad = SK_ScalarPI / n;
123         for (int i = 0; i < n; i++) {
124             *poly->push() = SkPoint::Make(c + SkScalarCos(rad) * r1, c + SkScalarSin(rad) * r1);
125             rad += drad;
126             *poly->push() = SkPoint::Make(c + SkScalarCos(rad) * r2, c + SkScalarSin(rad) * r2);
127             rad += drad;
128         }
129     }
130 private:
131     using INHERITED = PolyUtilsBench;
132 };
133 
134 class CirclePolyUtilsBench : public PolyUtilsBench {
135 public:
CirclePolyUtilsBench(PolyUtilsBench::Type type)136     CirclePolyUtilsBench(PolyUtilsBench::Type type) : INHERITED(type) {}
137 
appendName(SkString * name)138     void appendName(SkString* name) override {
139         name->append("circle");
140     }
makePoly(SkTDArray<SkPoint> * poly)141     void makePoly(SkTDArray<SkPoint>* poly) override {
142         // create circle with many vertices
143         const SkScalar c = SkIntToScalar(45);
144         const SkScalar r = SkIntToScalar(20);
145         const int n = 1000;
146         SkScalar rad = 0;
147         const SkScalar drad = 2 * SK_ScalarPI / n;
148         for (int i = 0; i < n; i++) {
149             *poly->push() = SkPoint::Make(c + SkScalarCos(rad) * r, c + SkScalarSin(rad) * r);
150             rad += drad;
151         }
152     }
153 private:
154     using INHERITED = PolyUtilsBench;
155 };
156 
157 class IntersectingPolyUtilsBench : public PolyUtilsBench {
158 public:
IntersectingPolyUtilsBench(PolyUtilsBench::Type type)159     IntersectingPolyUtilsBench(PolyUtilsBench::Type type) : INHERITED(type) {}
160 
appendName(SkString * name)161     void appendName(SkString* name) override {
162         name->append("intersecting");
163     }
makePoly(SkTDArray<SkPoint> * poly)164     void makePoly(SkTDArray<SkPoint>* poly) override {
165         // create self-intersecting star
166         const SkScalar c = SkIntToScalar(45);
167         const SkScalar r = SkIntToScalar(20);
168         const int n = 1000;
169 
170         SkScalar rad = -SK_ScalarPI / 2;
171         const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
172         *poly->push() = SkPoint::Make(c, c - r);
173         for (int i = 1; i < n; i++) {
174             rad += drad;
175             *poly->push() = SkPoint::Make(c + SkScalarCos(rad) * r, c + SkScalarSin(rad) * r);
176         }
177     }
178 private:
179     using INHERITED = PolyUtilsBench;
180 };
181 
182 // familiar videogame character
183 class NotchPolyUtilsBench : public PolyUtilsBench {
184 public:
NotchPolyUtilsBench(PolyUtilsBench::Type type)185     NotchPolyUtilsBench(PolyUtilsBench::Type type) : INHERITED(type) {}
186 
appendName(SkString * name)187     void appendName(SkString* name) override {
188         name->append("notch");
189     }
makePoly(SkTDArray<SkPoint> * poly)190     void makePoly(SkTDArray<SkPoint>* poly) override {
191         // create 3/4 circle with many vertices
192         const SkScalar c = SkIntToScalar(45);
193         const SkScalar r = SkIntToScalar(20);
194         const int n = 1000;
195         SkScalar rad = 0;
196         const SkScalar drad = 3 * SK_ScalarPI / (2*n);
197         for (int i = 0; i < n; i++) {
198             *poly->push() = SkPoint::Make(c + SkScalarCos(rad) * r, c + SkScalarSin(rad) * r);
199             rad += drad;
200         }
201         // and the mouth
202         *poly->push() = SkPoint::Make(45, 45);
203     }
204 private:
205     using INHERITED = PolyUtilsBench;
206 };
207 
208 class IceCreamPolyUtilsBench : public PolyUtilsBench {
209 public:
IceCreamPolyUtilsBench(PolyUtilsBench::Type type)210     IceCreamPolyUtilsBench(PolyUtilsBench::Type type) : INHERITED(type) {}
211 
appendName(SkString * name)212     void appendName(SkString* name) override {
213         name->append("icecream");
214     }
makePoly(SkTDArray<SkPoint> * poly)215     void makePoly(SkTDArray<SkPoint>* poly) override {
216         // create 3/4 circle with many vertices
217         const SkScalar c = SkIntToScalar(45);
218         const SkScalar r = SkIntToScalar(20);
219         const int n = 1000;
220         SkScalar rad = 0;
221         const SkScalar drad = 3 * SK_ScalarPI / (2*n);
222         for (int i = 0; i < n; i++) {
223             *poly->push() = SkPoint::Make(c + SkScalarCos(rad) * r, c + SkScalarSin(rad) * r);
224             rad += drad;
225         }
226         // and the tip of the cone
227         *poly->push() = SkPoint::Make(90, 0);
228     }
229 private:
230     using INHERITED = PolyUtilsBench;
231 };
232 
233 DEF_BENCH(return new StarPolyUtilsBench(PolyUtilsBench::Type::kConvexCheck);)
234 DEF_BENCH(return new StarPolyUtilsBench(PolyUtilsBench::Type::kSimpleCheck);)
235 DEF_BENCH(return new StarPolyUtilsBench(PolyUtilsBench::Type::kInsetConvex);)
236 DEF_BENCH(return new StarPolyUtilsBench(PolyUtilsBench::Type::kOffsetSimple);)
237 DEF_BENCH(return new StarPolyUtilsBench(PolyUtilsBench::Type::kTessellateSimple);)
238 DEF_BENCH(return new CirclePolyUtilsBench(PolyUtilsBench::Type::kConvexCheck);)
239 DEF_BENCH(return new CirclePolyUtilsBench(PolyUtilsBench::Type::kSimpleCheck);)
240 DEF_BENCH(return new CirclePolyUtilsBench(PolyUtilsBench::Type::kInsetConvex);)
241 DEF_BENCH(return new CirclePolyUtilsBench(PolyUtilsBench::Type::kOffsetSimple);)
242 DEF_BENCH(return new CirclePolyUtilsBench(PolyUtilsBench::Type::kTessellateSimple);)
243 DEF_BENCH(return new IntersectingPolyUtilsBench(PolyUtilsBench::Type::kConvexCheck);)
244 DEF_BENCH(return new IntersectingPolyUtilsBench(PolyUtilsBench::Type::kSimpleCheck);)
245 DEF_BENCH(return new IntersectingPolyUtilsBench(PolyUtilsBench::Type::kInsetConvex);)
246 DEF_BENCH(return new IntersectingPolyUtilsBench(PolyUtilsBench::Type::kOffsetSimple);)
247 DEF_BENCH(return new IntersectingPolyUtilsBench(PolyUtilsBench::Type::kTessellateSimple);)
248 DEF_BENCH(return new NotchPolyUtilsBench(PolyUtilsBench::Type::kConvexCheck);)
249 DEF_BENCH(return new NotchPolyUtilsBench(PolyUtilsBench::Type::kSimpleCheck);)
250 DEF_BENCH(return new NotchPolyUtilsBench(PolyUtilsBench::Type::kInsetConvex);)
251 DEF_BENCH(return new NotchPolyUtilsBench(PolyUtilsBench::Type::kOffsetSimple);)
252 DEF_BENCH(return new NotchPolyUtilsBench(PolyUtilsBench::Type::kTessellateSimple);)
253 DEF_BENCH(return new IceCreamPolyUtilsBench(PolyUtilsBench::Type::kConvexCheck);)
254 DEF_BENCH(return new IceCreamPolyUtilsBench(PolyUtilsBench::Type::kSimpleCheck);)
255 DEF_BENCH(return new IceCreamPolyUtilsBench(PolyUtilsBench::Type::kInsetConvex);)
256 DEF_BENCH(return new IceCreamPolyUtilsBench(PolyUtilsBench::Type::kOffsetSimple);)
257 DEF_BENCH(return new IceCreamPolyUtilsBench(PolyUtilsBench::Type::kTessellateSimple);)
258 
259