1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "Benchmark.h" 9 #include "SkBitmap.h" 10 #include "SkCanvas.h" 11 #include "SkColorPriv.h" 12 #include "SkGradientShader.h" 13 #include "SkPaint.h" 14 #include "SkShader.h" 15 #include "SkString.h" 16 17 struct GradData { 18 int fCount; 19 const SkColor* fColors; 20 const SkScalar* fPos; 21 const char* fName; 22 }; 23 24 static const SkColor gColors[] = { 25 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 26 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 27 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 28 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 29 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 30 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 31 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 32 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 33 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, 34 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, // 10 lines, 50 colors 35 }; 36 37 static const SkColor gShallowColors[] = { 0xFF555555, 0xFF444444 }; 38 39 // We have several special-cases depending on the number (and spacing) of colors, so 40 // try to exercise those here. 41 static const GradData gGradData[] = { 42 { 2, gColors, NULL, "" }, 43 { 50, gColors, NULL, "_hicolor" }, // many color gradient 44 { 3, gColors, NULL, "_3color" }, 45 { 2, gShallowColors, NULL, "_shallow" }, 46 }; 47 48 /// Ignores scale 49 static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, 50 SkShader::TileMode tm, float scale) { 51 return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, data.fCount, tm); 52 } 53 54 static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, 55 SkShader::TileMode tm, float scale) { 56 SkPoint center; 57 center.set(SkScalarAve(pts[0].fX, pts[1].fX), 58 SkScalarAve(pts[0].fY, pts[1].fY)); 59 return SkGradientShader::CreateRadial(center, center.fX * scale, 60 data.fColors, 61 data.fPos, data.fCount, tm); 62 } 63 64 /// Ignores scale 65 static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, 66 SkShader::TileMode tm, float scale) { 67 SkPoint center; 68 center.set(SkScalarAve(pts[0].fX, pts[1].fX), 69 SkScalarAve(pts[0].fY, pts[1].fY)); 70 return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, 71 data.fPos, data.fCount); 72 } 73 74 /// Ignores scale 75 static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, 76 SkShader::TileMode tm, float scale) { 77 SkPoint center0, center1; 78 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 79 SkScalarAve(pts[0].fY, pts[1].fY)); 80 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 81 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 82 return SkGradientShader::CreateTwoPointRadial( 83 center1, (pts[1].fX - pts[0].fX) / 7, 84 center0, (pts[1].fX - pts[0].fX) / 2, 85 data.fColors, data.fPos, data.fCount, tm); 86 } 87 88 /// Ignores scale 89 static SkShader* MakeConical(const SkPoint pts[2], const GradData& data, 90 SkShader::TileMode tm, float scale) { 91 SkPoint center0, center1; 92 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 93 SkScalarAve(pts[0].fY, pts[1].fY)); 94 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 95 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 96 return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, 97 center0, (pts[1].fX - pts[0].fX) / 2, 98 data.fColors, data.fPos, data.fCount, tm); 99 } 100 101 /// Ignores scale 102 static SkShader* MakeConicalZeroRad(const SkPoint pts[2], const GradData& data, 103 SkShader::TileMode tm, float scale) { 104 SkPoint center0, center1; 105 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 106 SkScalarAve(pts[0].fY, pts[1].fY)); 107 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 108 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 109 return SkGradientShader::CreateTwoPointConical(center1, 0.0, 110 center0, (pts[1].fX - pts[0].fX) / 2, 111 data.fColors, data.fPos, data.fCount, tm); 112 } 113 114 /// Ignores scale 115 static SkShader* MakeConicalOutside(const SkPoint pts[2], const GradData& data, 116 SkShader::TileMode tm, float scale) { 117 SkPoint center0, center1; 118 SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10); 119 SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3); 120 center0.set(pts[0].fX + radius0, pts[0].fY + radius0); 121 center1.set(pts[1].fX - radius1, pts[1].fY - radius1); 122 return SkGradientShader::CreateTwoPointConical(center0, radius0, 123 center1, radius1, 124 data.fColors, data.fPos, 125 data.fCount, tm); 126 } 127 128 /// Ignores scale 129 static SkShader* MakeConicalOutsideZeroRad(const SkPoint pts[2], const GradData& data, 130 SkShader::TileMode tm, float scale) { 131 SkPoint center0, center1; 132 SkScalar radius0 = SkScalarDiv(pts[1].fX - pts[0].fX, 10); 133 SkScalar radius1 = SkScalarDiv(pts[1].fX - pts[0].fX, 3); 134 center0.set(pts[0].fX + radius0, pts[0].fY + radius0); 135 center1.set(pts[1].fX - radius1, pts[1].fY - radius1); 136 return SkGradientShader::CreateTwoPointConical(center0, 0.0, 137 center1, radius1, 138 data.fColors, data.fPos, 139 data.fCount, tm); 140 } 141 142 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, 143 SkShader::TileMode tm, float scale); 144 145 static const struct { 146 GradMaker fMaker; 147 const char* fName; 148 } gGrads[] = { 149 { MakeLinear, "linear" }, 150 { MakeRadial, "radial1" }, 151 { MakeSweep, "sweep" }, 152 { Make2Radial, "radial2" }, 153 { MakeConical, "conical" }, 154 { MakeConicalZeroRad, "conicalZero" }, 155 { MakeConicalOutside, "conicalOut" }, 156 { MakeConicalOutsideZeroRad, "conicalOutZero" }, 157 }; 158 159 enum GradType { // these must match the order in gGrads 160 kLinear_GradType, 161 kRadial_GradType, 162 kSweep_GradType, 163 kRadial2_GradType, 164 kConical_GradType, 165 kConicalZero_GradType, 166 kConicalOut_GradType, 167 kConicalOutZero_GradType 168 }; 169 170 enum GeomType { 171 kRect_GeomType, 172 kOval_GeomType 173 }; 174 175 static const char* tilemodename(SkShader::TileMode tm) { 176 switch (tm) { 177 case SkShader::kClamp_TileMode: 178 return "clamp"; 179 case SkShader::kRepeat_TileMode: 180 return "repeat"; 181 case SkShader::kMirror_TileMode: 182 return "mirror"; 183 default: 184 SkDEBUGFAIL("unknown tilemode"); 185 return "error"; 186 } 187 } 188 189 static const char* geomtypename(GeomType gt) { 190 switch (gt) { 191 case kRect_GeomType: 192 return "rectangle"; 193 case kOval_GeomType: 194 return "oval"; 195 default: 196 SkDEBUGFAIL("unknown geometry type"); 197 return "error"; 198 } 199 } 200 201 /////////////////////////////////////////////////////////////////////////////// 202 203 class GradientBench : public Benchmark { 204 SkString fName; 205 SkShader* fShader; 206 bool fDither; 207 enum { 208 W = 400, 209 H = 400, 210 kRepeat = 15, 211 }; 212 public: 213 SkShader* makeShader(GradType gradType, GradData data, SkShader::TileMode tm, float scale) { 214 const SkPoint pts[2] = { 215 { 0, 0 }, 216 { SkIntToScalar(W), SkIntToScalar(H) } 217 }; 218 219 return gGrads[gradType].fMaker(pts, data, tm, scale); 220 } 221 222 GradientBench(GradType gradType, 223 GradData data = gGradData[0], 224 SkShader::TileMode tm = SkShader::kClamp_TileMode, 225 GeomType geomType = kRect_GeomType, 226 float scale = 1.0f) { 227 fName.printf("gradient_%s_%s", gGrads[gradType].fName, 228 tilemodename(tm)); 229 if (geomType != kRect_GeomType) { 230 fName.append("_"); 231 fName.append(geomtypename(geomType)); 232 } 233 234 if (scale != 1.f) { 235 fName.appendf("_scale_%g", scale); 236 } 237 238 fName.append(data.fName); 239 240 fDither = false; 241 fShader = this->makeShader(gradType, data, tm, scale); 242 fGeomType = geomType; 243 } 244 245 GradientBench(GradType gradType, GradData data, bool dither) { 246 const char *tmname = tilemodename(SkShader::kClamp_TileMode); 247 fName.printf("gradient_%s_%s", gGrads[gradType].fName, tmname); 248 fName.append(data.fName); 249 250 fDither = dither; 251 if (dither) { 252 fName.appendf("_dither"); 253 } 254 255 fShader = this->makeShader(gradType, data, SkShader::kClamp_TileMode, 1.0f); 256 fGeomType = kRect_GeomType; 257 } 258 259 virtual ~GradientBench() { 260 fShader->unref(); 261 } 262 263 protected: 264 virtual const char* onGetName() { 265 return fName.c_str(); 266 } 267 268 virtual void onDraw(const int loops, SkCanvas* canvas) { 269 SkPaint paint; 270 this->setupPaint(&paint); 271 272 paint.setShader(fShader); 273 if (fDither) { 274 paint.setDither(true); 275 } 276 277 SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) }; 278 for (int i = 0; i < loops * kRepeat; i++) { 279 switch (fGeomType) { 280 case kRect_GeomType: 281 canvas->drawRect(r, paint); 282 break; 283 case kOval_GeomType: 284 canvas->drawOval(r, paint); 285 break; 286 } 287 } 288 } 289 290 private: 291 typedef Benchmark INHERITED; 292 293 GeomType fGeomType; 294 }; 295 296 DEF_BENCH( return new GradientBench(kLinear_GradType); ) 297 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1]); ) 298 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2]); ) 299 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 300 301 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0]); ) 302 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[1]); ) 303 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[2]); ) 304 // Draw a radial gradient of radius 1/2 on a rectangle; half the lines should 305 // be completely pinned, the other half should pe partially pinned 306 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); ) 307 308 // Draw a radial gradient on a circle of equal size; all the lines should 309 // hit the unpinned fast path (so long as GradientBench.W == H) 310 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kOval_GeomType); ) 311 312 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 313 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kRepeat_TileMode); ) 314 DEF_BENCH( return new GradientBench(kSweep_GradType); ) 315 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); ) 316 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); ) 317 DEF_BENCH( return new GradientBench(kRadial2_GradType); ) 318 DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[1]); ) 319 DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 320 DEF_BENCH( return new GradientBench(kConical_GradType); ) 321 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); ) 322 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); ) 323 DEF_BENCH( return new GradientBench(kConicalZero_GradType); ) 324 DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[1]); ) 325 DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[2]); ) 326 DEF_BENCH( return new GradientBench(kConicalOut_GradType); ) 327 DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[1]); ) 328 DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[2]); ) 329 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType); ) 330 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[1]); ) 331 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[2]); ) 332 333 // Dithering 334 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], true); ) 335 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], false); ) 336 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], true); ) 337 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], false); ) 338 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], true); ) 339 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], false); ) 340 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], true); ) 341 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], false); ) 342 343 /////////////////////////////////////////////////////////////////////////////// 344 345 class Gradient2Bench : public Benchmark { 346 SkString fName; 347 bool fHasAlpha; 348 349 public: 350 Gradient2Bench(bool hasAlpha) { 351 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque"); 352 fHasAlpha = hasAlpha; 353 } 354 355 protected: 356 virtual const char* onGetName() { 357 return fName.c_str(); 358 } 359 360 virtual void onDraw(const int loops, SkCanvas* canvas) { 361 SkPaint paint; 362 this->setupPaint(&paint); 363 364 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) }; 365 const SkPoint pts[] = { 366 { 0, 0 }, 367 { SkIntToScalar(100), SkIntToScalar(100) }, 368 }; 369 370 for (int i = 0; i < loops; i++) { 371 const int gray = i % 256; 372 const int alpha = fHasAlpha ? gray : 0xFF; 373 SkColor colors[] = { 374 SK_ColorBLACK, 375 SkColorSetARGB(alpha, gray, gray, gray), 376 SK_ColorWHITE }; 377 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 378 SK_ARRAY_COUNT(colors), 379 SkShader::kClamp_TileMode); 380 paint.setShader(s)->unref(); 381 canvas->drawRect(r, paint); 382 } 383 } 384 385 private: 386 typedef Benchmark INHERITED; 387 }; 388 389 DEF_BENCH( return new Gradient2Bench(false); ) 390 DEF_BENCH( return new Gradient2Bench(true); ) 391