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 }; 211 public: 212 SkShader* makeShader(GradType gradType, GradData data, SkShader::TileMode tm, float scale) { 213 const SkPoint pts[2] = { 214 { 0, 0 }, 215 { SkIntToScalar(W), SkIntToScalar(H) } 216 }; 217 218 return gGrads[gradType].fMaker(pts, data, tm, scale); 219 } 220 221 GradientBench(GradType gradType, 222 GradData data = gGradData[0], 223 SkShader::TileMode tm = SkShader::kClamp_TileMode, 224 GeomType geomType = kRect_GeomType, 225 float scale = 1.0f) { 226 fName.printf("gradient_%s_%s", gGrads[gradType].fName, 227 tilemodename(tm)); 228 if (geomType != kRect_GeomType) { 229 fName.append("_"); 230 fName.append(geomtypename(geomType)); 231 } 232 233 if (scale != 1.f) { 234 fName.appendf("_scale_%g", scale); 235 } 236 237 fName.append(data.fName); 238 239 fDither = false; 240 fShader = this->makeShader(gradType, data, tm, scale); 241 fGeomType = geomType; 242 } 243 244 GradientBench(GradType gradType, GradData data, bool dither) { 245 const char *tmname = tilemodename(SkShader::kClamp_TileMode); 246 fName.printf("gradient_%s_%s", gGrads[gradType].fName, tmname); 247 fName.append(data.fName); 248 249 fDither = dither; 250 if (dither) { 251 fName.appendf("_dither"); 252 } 253 254 fShader = this->makeShader(gradType, data, SkShader::kClamp_TileMode, 1.0f); 255 fGeomType = kRect_GeomType; 256 } 257 258 virtual ~GradientBench() { 259 fShader->unref(); 260 } 261 262 protected: 263 virtual const char* onGetName() { 264 return fName.c_str(); 265 } 266 267 virtual void onDraw(const int loops, SkCanvas* canvas) { 268 SkPaint paint; 269 this->setupPaint(&paint); 270 271 paint.setShader(fShader); 272 if (fDither) { 273 paint.setDither(true); 274 } 275 276 SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) }; 277 for (int i = 0; i < loops; i++) { 278 switch (fGeomType) { 279 case kRect_GeomType: 280 canvas->drawRect(r, paint); 281 break; 282 case kOval_GeomType: 283 canvas->drawOval(r, paint); 284 break; 285 } 286 } 287 } 288 289 private: 290 typedef Benchmark INHERITED; 291 292 GeomType fGeomType; 293 }; 294 295 DEF_BENCH( return new GradientBench(kLinear_GradType); ) 296 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1]); ) 297 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2]); ) 298 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 299 300 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0]); ) 301 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[1]); ) 302 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[2]); ) 303 // Draw a radial gradient of radius 1/2 on a rectangle; half the lines should 304 // be completely pinned, the other half should pe partially pinned 305 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); ) 306 307 // Draw a radial gradient on a circle of equal size; all the lines should 308 // hit the unpinned fast path (so long as GradientBench.W == H) 309 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kOval_GeomType); ) 310 311 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 312 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kRepeat_TileMode); ) 313 DEF_BENCH( return new GradientBench(kSweep_GradType); ) 314 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); ) 315 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); ) 316 DEF_BENCH( return new GradientBench(kRadial2_GradType); ) 317 DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[1]); ) 318 DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 319 DEF_BENCH( return new GradientBench(kConical_GradType); ) 320 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); ) 321 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); ) 322 DEF_BENCH( return new GradientBench(kConicalZero_GradType); ) 323 DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[1]); ) 324 DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[2]); ) 325 DEF_BENCH( return new GradientBench(kConicalOut_GradType); ) 326 DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[1]); ) 327 DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[2]); ) 328 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType); ) 329 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[1]); ) 330 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[2]); ) 331 332 // Dithering 333 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], true); ) 334 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], false); ) 335 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], true); ) 336 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], false); ) 337 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], true); ) 338 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], false); ) 339 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], true); ) 340 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], false); ) 341 342 /////////////////////////////////////////////////////////////////////////////// 343 344 class Gradient2Bench : public Benchmark { 345 SkString fName; 346 bool fHasAlpha; 347 348 public: 349 Gradient2Bench(bool hasAlpha) { 350 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque"); 351 fHasAlpha = hasAlpha; 352 } 353 354 protected: 355 virtual const char* onGetName() { 356 return fName.c_str(); 357 } 358 359 virtual void onDraw(const int loops, SkCanvas* canvas) { 360 SkPaint paint; 361 this->setupPaint(&paint); 362 363 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) }; 364 const SkPoint pts[] = { 365 { 0, 0 }, 366 { SkIntToScalar(100), SkIntToScalar(100) }, 367 }; 368 369 for (int i = 0; i < loops; i++) { 370 const int gray = i % 256; 371 const int alpha = fHasAlpha ? gray : 0xFF; 372 SkColor colors[] = { 373 SK_ColorBLACK, 374 SkColorSetARGB(alpha, gray, gray, gray), 375 SK_ColorWHITE }; 376 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 377 SK_ARRAY_COUNT(colors), 378 SkShader::kClamp_TileMode); 379 paint.setShader(s)->unref(); 380 canvas->drawRect(r, paint); 381 } 382 } 383 384 private: 385 typedef Benchmark INHERITED; 386 }; 387 388 DEF_BENCH( return new Gradient2Bench(false); ) 389 DEF_BENCH( return new Gradient2Bench(true); ) 390