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