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