1 /* 2 * Copyright 2014 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/SkRRect.h" 10 #include "include/core/SkRect.h" 11 #include "src/base/SkRandom.h" 12 #include "src/core/SkGeometry.h" 13 #include "src/core/SkPathPriv.h" 14 15 class GeometryBench : public Benchmark { 16 public: GeometryBench(const char suffix[])17 GeometryBench(const char suffix[]) : fVolatileInt(0) { 18 fName.printf("geo_%s", suffix); 19 } 20 onGetName()21 const char* onGetName() override { 22 return fName.c_str(); 23 } 24 isSuitableFor(Backend backend)25 bool isSuitableFor(Backend backend) override { 26 return Backend::kNonRendering == backend; 27 } 28 29 protected: 30 volatile int fVolatileInt; 31 32 /** 33 * Subclasses can call this to try to defeat the optimizer (with some result of their 34 * inner loop), since it will fool the compiler into assuming that "n" is actually 35 * needed somewhere, and since this method is not const, the member fields cannot 36 * be assumed to be const before and after the call. 37 */ virtualCallToFoilOptimizers(int n)38 virtual void virtualCallToFoilOptimizers(int n) { 39 fVolatileInt = n; 40 } 41 42 private: 43 SkString fName; 44 }; 45 46 class GeoRectBench : public GeometryBench { 47 public: GeoRectBench(const char suffix[])48 GeoRectBench(const char suffix[]) : GeometryBench(suffix) {} 49 50 protected: 51 SkRect fRects[2048]; 52 onDelayedSetup()53 void onDelayedSetup() override { 54 const SkScalar min = -100; 55 const SkScalar max = 100; 56 SkRandom rand; 57 for (size_t i = 0; i < std::size(fRects); ++i) { 58 SkScalar x = rand.nextRangeScalar(min, max); 59 SkScalar y = rand.nextRangeScalar(min, max); 60 SkScalar w = rand.nextRangeScalar(min, max); 61 SkScalar h = rand.nextRangeScalar(min, max); 62 fRects[i].setXYWH(x, y, w, h); 63 } 64 } 65 }; 66 67 class GeoRectBench_intersect : public GeoRectBench { 68 public: GeoRectBench_intersect()69 GeoRectBench_intersect() : GeoRectBench("rect_intersect") {} 70 71 protected: onDraw(int loops,SkCanvas * canvas)72 void onDraw(int loops, SkCanvas* canvas) override { 73 for (int outer = 0; outer < loops; ++outer) { 74 int count = 0; 75 for (size_t i = 0; i < std::size(fRects); ++i) { 76 SkRect r = fRects[0]; 77 count += r.intersect(fRects[i]); 78 } 79 this->virtualCallToFoilOptimizers(count); 80 } 81 } 82 }; 83 84 class GeoRectBench_intersect_rect : public GeoRectBench { 85 public: GeoRectBench_intersect_rect()86 GeoRectBench_intersect_rect() : GeoRectBench("rect_intersect_rect") {} 87 88 protected: onDraw(int loops,SkCanvas * canvas)89 void onDraw(int loops, SkCanvas* canvas) override { 90 for (int outer = 0; outer < loops; ++outer) { 91 int count = 0; 92 SkRect r; 93 for (size_t i = 0; i < std::size(fRects); ++i) { 94 count += r.intersect(fRects[0], fRects[i]); 95 } 96 this->virtualCallToFoilOptimizers(count); 97 } 98 } 99 }; 100 101 class GeoRectBench_Intersects : public GeoRectBench { 102 public: GeoRectBench_Intersects()103 GeoRectBench_Intersects() : GeoRectBench("rect_Intersects") {} 104 105 protected: onDraw(int loops,SkCanvas * canvas)106 void onDraw(int loops, SkCanvas* canvas) override { 107 for (int outer = 0; outer < loops; ++outer) { 108 int count = 0; 109 for (size_t i = 0; i < std::size(fRects); ++i) { 110 count += SkRect::Intersects(fRects[0], fRects[i]); 111 } 112 this->virtualCallToFoilOptimizers(count); 113 } 114 } 115 }; 116 117 class GeoRectBench_sort : public GeoRectBench { 118 public: GeoRectBench_sort()119 GeoRectBench_sort() : GeoRectBench("rect_sort") {} 120 121 protected: onDraw(int loops,SkCanvas * canvas)122 void onDraw(int loops, SkCanvas* canvas) override { 123 for (int outer = 0; outer < loops; ++outer) { 124 for (size_t i = 0; i < std::size(fRects); ++i) { 125 fRects[i].sort(); 126 } 127 } 128 } 129 }; 130 131 DEF_BENCH( return new GeoRectBench_intersect; ) 132 DEF_BENCH( return new GeoRectBench_intersect_rect; ) 133 DEF_BENCH( return new GeoRectBench_Intersects; ) 134 135 DEF_BENCH( return new GeoRectBench_sort; ) 136 137 /////////////////////////////////////////////////////////////////////////////////////////////////// 138 139 class QuadBenchBase : public GeometryBench { 140 protected: 141 SkPoint fPts[4]; 142 public: QuadBenchBase(const char name[])143 QuadBenchBase(const char name[]) : GeometryBench(name) { 144 SkRandom rand; 145 for (int i = 0; i < 4; ++i) { 146 fPts[i].set(rand.nextUScalar1(), rand.nextUScalar1()); 147 } 148 } 149 }; 150 151 class EvalQuadAt0 : public QuadBenchBase { 152 public: EvalQuadAt0()153 EvalQuadAt0() : QuadBenchBase("evalquadat0") {} 154 protected: onDraw(int loops,SkCanvas * canvas)155 void onDraw(int loops, SkCanvas* canvas) override { 156 SkPoint result; 157 for (int outer = 0; outer < loops; ++outer) { 158 SkEvalQuadAt(fPts, 0.5f, &result); 159 SkEvalQuadAt(fPts, 0.5f, &result); 160 SkEvalQuadAt(fPts, 0.5f, &result); 161 SkEvalQuadAt(fPts, 0.5f, &result); 162 } 163 } 164 }; 165 DEF_BENCH( return new EvalQuadAt0; ) 166 167 class EvalQuadAt1 : public QuadBenchBase { 168 public: EvalQuadAt1()169 EvalQuadAt1() : QuadBenchBase("evalquadat1") {} 170 protected: onDraw(int loops,SkCanvas * canvas)171 void onDraw(int loops, SkCanvas* canvas) override { 172 SkPoint result; 173 for (int outer = 0; outer < loops; ++outer) { 174 result = SkEvalQuadAt(fPts, 0.5f); 175 result = SkEvalQuadAt(fPts, 0.5f); 176 result = SkEvalQuadAt(fPts, 0.5f); 177 result = SkEvalQuadAt(fPts, 0.5f); 178 } 179 } 180 }; 181 DEF_BENCH( return new EvalQuadAt1; ) 182 183 //////// 184 185 class EvalQuadTangentAt0 : public QuadBenchBase { 186 public: EvalQuadTangentAt0()187 EvalQuadTangentAt0() : QuadBenchBase("evalquadtangentat0") {} 188 protected: onDraw(int loops,SkCanvas * canvas)189 void onDraw(int loops, SkCanvas* canvas) override { 190 SkPoint result; 191 for (int outer = 0; outer < loops; ++outer) { 192 SkEvalQuadAt(fPts, 0.5f, nullptr, &result); 193 SkEvalQuadAt(fPts, 0.5f, nullptr, &result); 194 SkEvalQuadAt(fPts, 0.5f, nullptr, &result); 195 SkEvalQuadAt(fPts, 0.5f, nullptr, &result); 196 } 197 } 198 }; 199 DEF_BENCH( return new EvalQuadTangentAt0; ) 200 201 class EvalQuadTangentAt1 : public QuadBenchBase { 202 public: EvalQuadTangentAt1()203 EvalQuadTangentAt1() : QuadBenchBase("evalquadtangentat1") {} 204 protected: onDraw(int loops,SkCanvas * canvas)205 void onDraw(int loops, SkCanvas* canvas) override { 206 SkPoint result; 207 for (int outer = 0; outer < loops; ++outer) { 208 result = SkEvalQuadTangentAt(fPts, 0.5f); 209 result = SkEvalQuadTangentAt(fPts, 0.5f); 210 result = SkEvalQuadTangentAt(fPts, 0.5f); 211 result = SkEvalQuadTangentAt(fPts, 0.5f); 212 } 213 } 214 }; 215 DEF_BENCH( return new EvalQuadTangentAt1; ) 216 217 //////// 218 219 class ChopQuadAt : public QuadBenchBase { 220 public: ChopQuadAt()221 ChopQuadAt() : QuadBenchBase("chopquadat") {} 222 protected: onDraw(int loops,SkCanvas * canvas)223 void onDraw(int loops, SkCanvas* canvas) override { 224 SkPoint dst[5]; 225 for (int outer = 0; outer < loops; ++outer) { 226 SkChopQuadAt(fPts, dst, 0.5f); 227 SkChopQuadAt(fPts, dst, 0.5f); 228 SkChopQuadAt(fPts, dst, 0.5f); 229 SkChopQuadAt(fPts, dst, 0.5f); 230 } 231 } 232 }; 233 DEF_BENCH( return new ChopQuadAt; ) 234 235 class ChopCubicAt : public QuadBenchBase { 236 public: ChopCubicAt()237 ChopCubicAt() : QuadBenchBase("chopcubicat0") {} 238 protected: onDraw(int loops,SkCanvas * canvas)239 void onDraw(int loops, SkCanvas* canvas) override { 240 SkPoint dst[7]; 241 for (int outer = 0; outer < loops; ++outer) { 242 SkChopCubicAt(fPts, dst, 0.5f); 243 SkChopCubicAt(fPts, dst, 0.5f); 244 SkChopCubicAt(fPts, dst, 0.5f); 245 SkChopCubicAt(fPts, dst, 0.5f); 246 } 247 } 248 }; 249 DEF_BENCH( return new ChopCubicAt; ) 250 251 #include "include/core/SkPath.h" 252 253 class ConvexityBench : public Benchmark { 254 SkPath fPath; 255 256 public: ConvexityBench(const char suffix[])257 ConvexityBench(const char suffix[]) { 258 fName.printf("convexity_%s", suffix); 259 } 260 onGetName()261 const char* onGetName() override { 262 return fName.c_str(); 263 } 264 isSuitableFor(Backend backend)265 bool isSuitableFor(Backend backend) override { 266 return Backend::kNonRendering == backend; 267 } 268 269 virtual void preparePath(SkPath*) = 0; 270 271 protected: onPreDraw(SkCanvas *)272 void onPreDraw(SkCanvas*) override { 273 this->preparePath(&fPath); 274 } 275 onDraw(int loops,SkCanvas * canvas)276 void onDraw(int loops, SkCanvas* canvas) override { 277 for (int i = 0; i < loops; ++i) { 278 SkPathPriv::ForceComputeConvexity(fPath); 279 } 280 } 281 282 private: 283 SkString fName; 284 }; 285 286 class RRectConvexityBench : public ConvexityBench { 287 public: RRectConvexityBench()288 RRectConvexityBench() : ConvexityBench("rrect") {} 289 preparePath(SkPath * path)290 void preparePath(SkPath* path) override { 291 SkRRect rr; 292 rr.setRectXY({0, 0, 100, 100}, 20, 30); 293 path->addRRect(rr); 294 } 295 }; 296 DEF_BENCH( return new RRectConvexityBench; ) 297 298