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 17struct GradData { 18 int fCount; 19 const SkColor* fColors; 20 const SkScalar* fPos; 21 const char* fName; 22}; 23 24static 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 37static 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. 41static 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 49static 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 54static 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 65static 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 75static 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 89static 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 102static 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 115static 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 129static 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 142typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, 143 SkShader::TileMode tm, float scale); 144 145static 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 159enum 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 170enum GeomType { 171 kRect_GeomType, 172 kOval_GeomType 173}; 174 175static 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 189static 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 203class GradientBench : public Benchmark { 204 SkString fName; 205 SkShader* fShader; 206 bool fDither; 207 enum { 208 W = 400, 209 H = 400, 210 }; 211public: 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 262protected: 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 289private: 290 typedef Benchmark INHERITED; 291 292 GeomType fGeomType; 293}; 294 295DEF_BENCH( return new GradientBench(kLinear_GradType); ) 296DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1]); ) 297DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2]); ) 298DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 299 300DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0]); ) 301DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[1]); ) 302DEF_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 305DEF_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) 309DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kOval_GeomType); ) 310 311DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 312DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kRepeat_TileMode); ) 313DEF_BENCH( return new GradientBench(kSweep_GradType); ) 314DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); ) 315DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); ) 316DEF_BENCH( return new GradientBench(kRadial2_GradType); ) 317DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[1]); ) 318DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 319DEF_BENCH( return new GradientBench(kConical_GradType); ) 320DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); ) 321DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); ) 322DEF_BENCH( return new GradientBench(kConicalZero_GradType); ) 323DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[1]); ) 324DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[2]); ) 325DEF_BENCH( return new GradientBench(kConicalOut_GradType); ) 326DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[1]); ) 327DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[2]); ) 328DEF_BENCH( return new GradientBench(kConicalOutZero_GradType); ) 329DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[1]); ) 330DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[2]); ) 331 332// Dithering 333DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], true); ) 334DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], false); ) 335DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], true); ) 336DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], false); ) 337DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], true); ) 338DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], false); ) 339DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], true); ) 340DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], false); ) 341 342/////////////////////////////////////////////////////////////////////////////// 343 344class Gradient2Bench : public Benchmark { 345 SkString fName; 346 bool fHasAlpha; 347 348public: 349 Gradient2Bench(bool hasAlpha) { 350 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque"); 351 fHasAlpha = hasAlpha; 352 } 353 354protected: 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 384private: 385 typedef Benchmark INHERITED; 386}; 387 388DEF_BENCH( return new Gradient2Bench(false); ) 389DEF_BENCH( return new Gradient2Bench(true); ) 390