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