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