1 /* 2 * Copyright 2011 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/SkBitmap.h" 10 #include "include/core/SkCanvas.h" 11 #include "include/core/SkPaint.h" 12 #include "include/core/SkShader.h" 13 #include "include/core/SkString.h" 14 #include "include/effects/SkGradientShader.h" 15 #include "include/utils/SkRandom.h" 16 #include "tools/flags/CommandLineFlags.h" 17 18 static DEFINE_double(strokeWidth, -1.0, "If set, use this stroke width in RectBench."); 19 20 class RectBench : public Benchmark { 21 public: 22 int fShift, fStroke; 23 enum { 24 W = 640, 25 H = 480, 26 N = 300, 27 }; 28 SkRect fRects[N]; 29 SkColor fColors[N]; 30 bool fAA; 31 bool fPerspective; 32 RectBench(int shift,int stroke=0,bool aa=true,bool perspective=false)33 RectBench(int shift, int stroke = 0, bool aa = true, bool perspective = false) 34 : fShift(shift) 35 , fStroke(stroke) 36 , fAA(aa) 37 , fPerspective(perspective) {} 38 computeName(const char root[])39 const char* computeName(const char root[]) { 40 fBaseName.printf("%s_%d", root, fShift); 41 if (fStroke > 0) { 42 fBaseName.appendf("_stroke_%d", fStroke); 43 } 44 if (fAA) { 45 fBaseName.appendf("_aa"); 46 } else { 47 fBaseName.appendf("_bw"); 48 } 49 if (fPerspective) { 50 fBaseName.appendf("_persp"); 51 } 52 return fBaseName.c_str(); 53 } 54 55 protected: 56 drawThisRect(SkCanvas * c,const SkRect & r,const SkPaint & p)57 virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) { 58 c->drawRect(r, p); 59 } 60 onGetName()61 const char* onGetName() override { return computeName("rects"); } 62 onDelayedSetup()63 void onDelayedSetup() override { 64 SkRandom rand; 65 const SkScalar offset = SK_Scalar1/3; 66 for (int i = 0; i < N; i++) { 67 int x = rand.nextU() % W; 68 int y = rand.nextU() % H; 69 int w = rand.nextU() % W; 70 int h = rand.nextU() % H; 71 w >>= fShift; 72 h >>= fShift; 73 x -= w/2; 74 y -= h/2; 75 fRects[i].setXYWH(SkIntToScalar(x), SkIntToScalar(y), 76 SkIntToScalar(w), SkIntToScalar(h)); 77 fRects[i].offset(offset, offset); 78 fColors[i] = rand.nextU() | 0xFF808080; 79 } 80 } 81 onDraw(int loops,SkCanvas * canvas)82 void onDraw(int loops, SkCanvas* canvas) override { 83 SkPaint paint; 84 if (fStroke > 0) { 85 paint.setStyle(SkPaint::kStroke_Style); 86 paint.setStrokeWidth(SkIntToScalar(fStroke)); 87 } 88 if (fPerspective) { 89 // Apply some fixed perspective to change how ops may draw the rects 90 SkMatrix perspective; 91 perspective.setIdentity(); 92 perspective.setPerspX(1e-4f); 93 perspective.setPerspY(1e-3f); 94 perspective.setSkewX(0.1f); 95 canvas->concat(perspective); 96 } 97 for (int i = 0; i < loops; i++) { 98 paint.setColor(fColors[i % N]); 99 this->setupPaint(&paint); 100 this->drawThisRect(canvas, fRects[i % N], paint); 101 } 102 } 103 setupPaint(SkPaint * paint)104 void setupPaint(SkPaint* paint) override { 105 this->INHERITED::setupPaint(paint); 106 paint->setAntiAlias(fAA); 107 } 108 109 private: 110 SkString fBaseName; 111 using INHERITED = Benchmark; 112 }; 113 114 class SrcModeRectBench : public RectBench { 115 public: SrcModeRectBench()116 SrcModeRectBench() : INHERITED(1, 0) { 117 fMode = SkBlendMode::kSrc; 118 } 119 120 protected: setupPaint(SkPaint * paint)121 void setupPaint(SkPaint* paint) override { 122 this->INHERITED::setupPaint(paint); 123 // srcmode is most interesting when we're not opaque 124 paint->setAlpha(0x80); 125 paint->setBlendMode(fMode); 126 } 127 onGetName()128 const char* onGetName() override { 129 fName.set(this->INHERITED::onGetName()); 130 fName.prepend("srcmode_"); 131 return fName.c_str(); 132 } 133 134 private: 135 SkBlendMode fMode; 136 SkString fName; 137 138 using INHERITED = RectBench; 139 }; 140 141 class TransparentRectBench : public RectBench { 142 public: TransparentRectBench()143 TransparentRectBench() : INHERITED(1, 0) {} 144 145 protected: setupPaint(SkPaint * paint)146 void setupPaint(SkPaint* paint) override { 147 this->INHERITED::setupPaint(paint); 148 // draw non opaque rect 149 paint->setAlpha(0x80); 150 } 151 onGetName()152 const char* onGetName() override { 153 fName.set(this->INHERITED::onGetName()); 154 fName.prepend("transparent_"); 155 return fName.c_str(); 156 } 157 158 private: 159 SkString fName; 160 using INHERITED = RectBench; 161 }; 162 163 // Adds a shader to the paint that requires local coordinates to be used 164 class LocalCoordsRectBench : public RectBench { 165 public: LocalCoordsRectBench(bool aa,bool perspective=false)166 LocalCoordsRectBench(bool aa, bool perspective = false) : INHERITED(1, 0, aa, perspective) { } 167 168 protected: onDelayedSetup()169 void onDelayedSetup() override { 170 this->INHERITED::onDelayedSetup(); 171 // Create the shader once, so that isn't included in the timing 172 SkPoint pts[2] = { {0.f, 0.f}, {50.f, 50.f} }; 173 SkColor colors[] = { SK_ColorWHITE, SK_ColorBLUE }; 174 fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp); 175 } 176 setupPaint(SkPaint * paint)177 void setupPaint(SkPaint* paint) override { 178 this->INHERITED::setupPaint(paint); 179 paint->setShader(fShader); 180 } 181 onGetName()182 const char* onGetName() override { 183 fName.set(this->INHERITED::onGetName()); 184 fName.append("_localcoords"); 185 return fName.c_str(); 186 } 187 188 private: 189 SkString fName; 190 sk_sp<SkShader> fShader; 191 192 using INHERITED = RectBench; 193 }; 194 195 196 class OvalBench : public RectBench { 197 public: OvalBench(int shift,int stroke=0)198 OvalBench(int shift, int stroke = 0) : RectBench(shift, stroke) {} 199 protected: drawThisRect(SkCanvas * c,const SkRect & r,const SkPaint & p)200 void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) override { 201 c->drawOval(r, p); 202 } onGetName()203 const char* onGetName() override { return computeName("ovals"); } 204 }; 205 206 class RRectBench : public RectBench { 207 public: RRectBench(int shift,int stroke=0)208 RRectBench(int shift, int stroke = 0) : RectBench(shift, stroke) {} 209 protected: drawThisRect(SkCanvas * c,const SkRect & r,const SkPaint & p)210 void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) override { 211 c->drawRoundRect(r, r.width() / 4, r.height() / 4, p); 212 } onGetName()213 const char* onGetName() override { return computeName("rrects"); } 214 }; 215 216 class PointsBench : public RectBench { 217 public: 218 SkCanvas::PointMode fMode; 219 PointsBench(SkCanvas::PointMode mode,const char * name)220 PointsBench(SkCanvas::PointMode mode, const char* name) 221 : RectBench(2) 222 , fMode(mode) { 223 fName = name; 224 } 225 226 protected: onDraw(int loops,SkCanvas * canvas)227 void onDraw(int loops, SkCanvas* canvas) override { 228 SkScalar gSizes[] = { 229 SkIntToScalar(7), 0 230 }; 231 size_t sizes = SK_ARRAY_COUNT(gSizes); 232 233 if (FLAGS_strokeWidth >= 0) { 234 gSizes[0] = (SkScalar)FLAGS_strokeWidth; 235 sizes = 1; 236 } 237 238 SkPaint paint; 239 paint.setStrokeCap(SkPaint::kRound_Cap); 240 241 for (int loop = 0; loop < loops; loop++) { 242 for (size_t i = 0; i < sizes; i++) { 243 paint.setStrokeWidth(gSizes[i]); 244 this->setupPaint(&paint); 245 canvas->drawPoints(fMode, N * 2, reinterpret_cast<SkPoint*>(fRects), paint); 246 paint.setColor(fColors[i % N]); 247 } 248 } 249 } onGetName()250 const char* onGetName() override { return fName.c_str(); } 251 252 private: 253 SkString fName; 254 255 }; 256 257 /******************************************************************************* 258 * to bench BlitMask [Opaque, Black, color, shader] 259 *******************************************************************************/ 260 261 class BlitMaskBench : public RectBench { 262 public: 263 enum kMaskType { 264 kMaskOpaque = 0, 265 kMaskBlack, 266 kMaskColor, 267 KMaskShader 268 }; 269 SkCanvas::PointMode fMode; 270 BlitMaskBench(SkCanvas::PointMode mode,BlitMaskBench::kMaskType type,const char * name)271 BlitMaskBench(SkCanvas::PointMode mode, 272 BlitMaskBench::kMaskType type, const char* name) : 273 RectBench(2), fMode(mode), _type(type) { 274 fName = name; 275 } 276 277 protected: onDraw(int loops,SkCanvas * canvas)278 void onDraw(int loops, SkCanvas* canvas) override { 279 SkScalar gSizes[] = { 280 SkIntToScalar(13), SkIntToScalar(24) 281 }; 282 size_t sizes = SK_ARRAY_COUNT(gSizes); 283 284 if (FLAGS_strokeWidth >= 0) { 285 gSizes[0] = (SkScalar)FLAGS_strokeWidth; 286 sizes = 1; 287 } 288 SkRandom rand; 289 SkColor color = 0xFF000000; 290 U8CPU alpha = 0xFF; 291 SkPaint paint; 292 paint.setStrokeCap(SkPaint::kRound_Cap); 293 if (_type == KMaskShader) { 294 SkBitmap srcBM; 295 srcBM.allocN32Pixels(10, 1); 296 srcBM.eraseColor(0xFF00FF00); 297 298 paint.setShader(srcBM.makeShader(SkSamplingOptions())); 299 } 300 for (int loop = 0; loop < loops; loop++) { 301 for (size_t i = 0; i < sizes; i++) { 302 switch (_type) { 303 case kMaskOpaque: 304 color = fColors[i]; 305 alpha = 0xFF; 306 break; 307 case kMaskBlack: 308 alpha = 0xFF; 309 color = 0xFF000000; 310 break; 311 case kMaskColor: 312 color = fColors[i]; 313 alpha = rand.nextU() & 255; 314 break; 315 case KMaskShader: 316 break; 317 } 318 paint.setStrokeWidth(gSizes[i]); 319 this->setupPaint(&paint); 320 paint.setColor(color); 321 paint.setAlpha(alpha); 322 canvas->drawPoints(fMode, N * 2, reinterpret_cast<SkPoint*>(fRects), paint); 323 } 324 } 325 } onGetName()326 const char* onGetName() override { return fName.c_str(); } 327 328 private: 329 using INHERITED = RectBench; 330 kMaskType _type; 331 SkString fName; 332 }; 333 334 // AA rects 335 DEF_BENCH(return new RectBench(1, 0, true);) 336 DEF_BENCH(return new RectBench(1, 4, true);) 337 DEF_BENCH(return new RectBench(3, 0, true);) 338 DEF_BENCH(return new RectBench(3, 4, true);) 339 // Non-AA rects 340 DEF_BENCH(return new RectBench(1, 0, false);) 341 DEF_BENCH(return new RectBench(1, 4, false);) 342 DEF_BENCH(return new RectBench(3, 0, false);) 343 DEF_BENCH(return new RectBench(3, 4, false);) 344 345 DEF_BENCH(return new OvalBench(1);) 346 DEF_BENCH(return new OvalBench(3);) 347 DEF_BENCH(return new OvalBench(1, 4);) 348 DEF_BENCH(return new OvalBench(3, 4);) 349 DEF_BENCH(return new RRectBench(1);) 350 DEF_BENCH(return new RRectBench(1, 4);) 351 DEF_BENCH(return new RRectBench(3);) 352 DEF_BENCH(return new RRectBench(3, 4);) 353 DEF_BENCH(return new PointsBench(SkCanvas::kPoints_PointMode, "points");) 354 DEF_BENCH(return new PointsBench(SkCanvas::kLines_PointMode, "lines");) 355 DEF_BENCH(return new PointsBench(SkCanvas::kPolygon_PointMode, "polygon");) 356 357 DEF_BENCH(return new SrcModeRectBench();) 358 359 DEF_BENCH(return new TransparentRectBench();) 360 361 DEF_BENCH(return new LocalCoordsRectBench(true);) 362 DEF_BENCH(return new LocalCoordsRectBench(false);) 363 364 // Perspective rects 365 DEF_BENCH(return new RectBench(1, 0, true, true);) 366 DEF_BENCH(return new RectBench(1, 0, false, true);) 367 DEF_BENCH(return new LocalCoordsRectBench(true, true);) 368 DEF_BENCH(return new LocalCoordsRectBench(false, true);) 369 370 /* init the blitmask bench 371 */ 372 DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode, 373 BlitMaskBench::kMaskOpaque, 374 "maskopaque");) 375 DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode, 376 BlitMaskBench::kMaskBlack, 377 "maskblack");) 378 DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode, 379 BlitMaskBench::kMaskColor, 380 "maskcolor");) 381 DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode, 382 BlitMaskBench::KMaskShader, 383 "maskshader");) 384