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