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* MakeConical(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::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, 83 center0, (pts[1].fX - pts[0].fX) / 2, 84 data.fColors, data.fPos, data.fCount, tm); 85} 86 87/// Ignores scale 88static SkShader* MakeConicalZeroRad(const SkPoint pts[2], const GradData& data, 89 SkShader::TileMode tm, float scale) { 90 SkPoint center0, center1; 91 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 92 SkScalarAve(pts[0].fY, pts[1].fY)); 93 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 94 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 95 return SkGradientShader::CreateTwoPointConical(center1, 0.0, 96 center0, (pts[1].fX - pts[0].fX) / 2, 97 data.fColors, data.fPos, data.fCount, tm); 98} 99 100/// Ignores scale 101static SkShader* MakeConicalOutside(const SkPoint pts[2], const GradData& data, 102 SkShader::TileMode tm, float scale) { 103 SkPoint center0, center1; 104 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10; 105 SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3; 106 center0.set(pts[0].fX + radius0, pts[0].fY + radius0); 107 center1.set(pts[1].fX - radius1, pts[1].fY - radius1); 108 return SkGradientShader::CreateTwoPointConical(center0, radius0, 109 center1, radius1, 110 data.fColors, data.fPos, 111 data.fCount, tm); 112} 113 114/// Ignores scale 115static SkShader* MakeConicalOutsideZeroRad(const SkPoint pts[2], const GradData& data, 116 SkShader::TileMode tm, float scale) { 117 SkPoint center0, center1; 118 SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10; 119 SkScalar radius1 = (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, 0.0, 123 center1, radius1, 124 data.fColors, data.fPos, 125 data.fCount, tm); 126} 127 128typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, 129 SkShader::TileMode tm, float scale); 130 131static const struct { 132 GradMaker fMaker; 133 const char* fName; 134} gGrads[] = { 135 { MakeLinear, "linear" }, 136 { MakeRadial, "radial1" }, 137 { MakeSweep, "sweep" }, 138 { MakeConical, "conical" }, 139 { MakeConicalZeroRad, "conicalZero" }, 140 { MakeConicalOutside, "conicalOut" }, 141 { MakeConicalOutsideZeroRad, "conicalOutZero" }, 142}; 143 144enum GradType { // these must match the order in gGrads 145 kLinear_GradType, 146 kRadial_GradType, 147 kSweep_GradType, 148 kConical_GradType, 149 kConicalZero_GradType, 150 kConicalOut_GradType, 151 kConicalOutZero_GradType 152}; 153 154enum GeomType { 155 kRect_GeomType, 156 kOval_GeomType 157}; 158 159static const char* tilemodename(SkShader::TileMode tm) { 160 switch (tm) { 161 case SkShader::kClamp_TileMode: 162 return "clamp"; 163 case SkShader::kRepeat_TileMode: 164 return "repeat"; 165 case SkShader::kMirror_TileMode: 166 return "mirror"; 167 default: 168 SkDEBUGFAIL("unknown tilemode"); 169 return "error"; 170 } 171} 172 173static const char* geomtypename(GeomType gt) { 174 switch (gt) { 175 case kRect_GeomType: 176 return "rectangle"; 177 case kOval_GeomType: 178 return "oval"; 179 default: 180 SkDEBUGFAIL("unknown geometry type"); 181 return "error"; 182 } 183} 184 185/////////////////////////////////////////////////////////////////////////////// 186 187class GradientBench : public Benchmark { 188 SkString fName; 189 SkShader* fShader; 190 bool fDither; 191 enum { 192 W = 400, 193 H = 400, 194 }; 195public: 196 SkShader* makeShader(GradType gradType, GradData data, SkShader::TileMode tm, float scale) { 197 const SkPoint pts[2] = { 198 { 0, 0 }, 199 { SkIntToScalar(W), SkIntToScalar(H) } 200 }; 201 202 return gGrads[gradType].fMaker(pts, data, tm, scale); 203 } 204 205 GradientBench(GradType gradType, 206 GradData data = gGradData[0], 207 SkShader::TileMode tm = SkShader::kClamp_TileMode, 208 GeomType geomType = kRect_GeomType, 209 float scale = 1.0f) { 210 fName.printf("gradient_%s_%s", gGrads[gradType].fName, 211 tilemodename(tm)); 212 if (geomType != kRect_GeomType) { 213 fName.append("_"); 214 fName.append(geomtypename(geomType)); 215 } 216 217 if (scale != 1.f) { 218 fName.appendf("_scale_%g", scale); 219 } 220 221 fName.append(data.fName); 222 223 fDither = false; 224 fShader = this->makeShader(gradType, data, tm, scale); 225 fGeomType = geomType; 226 } 227 228 GradientBench(GradType gradType, GradData data, bool dither) { 229 const char *tmname = tilemodename(SkShader::kClamp_TileMode); 230 fName.printf("gradient_%s_%s", gGrads[gradType].fName, tmname); 231 fName.append(data.fName); 232 233 fDither = dither; 234 if (dither) { 235 fName.appendf("_dither"); 236 } 237 238 fShader = this->makeShader(gradType, data, SkShader::kClamp_TileMode, 1.0f); 239 fGeomType = kRect_GeomType; 240 } 241 242 virtual ~GradientBench() { 243 fShader->unref(); 244 } 245 246protected: 247 virtual const char* onGetName() { 248 return fName.c_str(); 249 } 250 251 virtual void onDraw(const int loops, SkCanvas* canvas) { 252 SkPaint paint; 253 this->setupPaint(&paint); 254 255 paint.setShader(fShader); 256 if (fDither) { 257 paint.setDither(true); 258 } 259 260 SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) }; 261 for (int i = 0; i < loops; i++) { 262 switch (fGeomType) { 263 case kRect_GeomType: 264 canvas->drawRect(r, paint); 265 break; 266 case kOval_GeomType: 267 canvas->drawOval(r, paint); 268 break; 269 } 270 } 271 } 272 273private: 274 typedef Benchmark INHERITED; 275 276 GeomType fGeomType; 277}; 278 279DEF_BENCH( return new GradientBench(kLinear_GradType); ) 280DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1]); ) 281DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2]); ) 282DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 283 284DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0]); ) 285DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[1]); ) 286DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[2]); ) 287// Draw a radial gradient of radius 1/2 on a rectangle; half the lines should 288// be completely pinned, the other half should pe partially pinned 289DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); ) 290 291// Draw a radial gradient on a circle of equal size; all the lines should 292// hit the unpinned fast path (so long as GradientBench.W == H) 293DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kOval_GeomType); ) 294 295DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 296DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kRepeat_TileMode); ) 297DEF_BENCH( return new GradientBench(kSweep_GradType); ) 298DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); ) 299DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); ) 300DEF_BENCH( return new GradientBench(kConical_GradType); ) 301DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); ) 302DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); ) 303DEF_BENCH( return new GradientBench(kConicalZero_GradType); ) 304DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[1]); ) 305DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[2]); ) 306DEF_BENCH( return new GradientBench(kConicalOut_GradType); ) 307DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[1]); ) 308DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[2]); ) 309DEF_BENCH( return new GradientBench(kConicalOutZero_GradType); ) 310DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[1]); ) 311DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[2]); ) 312 313// Dithering 314DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], true); ) 315DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], false); ) 316DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], true); ) 317DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], false); ) 318DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], true); ) 319DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], false); ) 320DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], true); ) 321DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], false); ) 322 323/////////////////////////////////////////////////////////////////////////////// 324 325class Gradient2Bench : public Benchmark { 326 SkString fName; 327 bool fHasAlpha; 328 329public: 330 Gradient2Bench(bool hasAlpha) { 331 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque"); 332 fHasAlpha = hasAlpha; 333 } 334 335protected: 336 virtual const char* onGetName() { 337 return fName.c_str(); 338 } 339 340 virtual void onDraw(const int loops, SkCanvas* canvas) { 341 SkPaint paint; 342 this->setupPaint(&paint); 343 344 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) }; 345 const SkPoint pts[] = { 346 { 0, 0 }, 347 { SkIntToScalar(100), SkIntToScalar(100) }, 348 }; 349 350 for (int i = 0; i < loops; i++) { 351 const int gray = i % 256; 352 const int alpha = fHasAlpha ? gray : 0xFF; 353 SkColor colors[] = { 354 SK_ColorBLACK, 355 SkColorSetARGB(alpha, gray, gray, gray), 356 SK_ColorWHITE }; 357 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 358 SK_ARRAY_COUNT(colors), 359 SkShader::kClamp_TileMode); 360 paint.setShader(s)->unref(); 361 canvas->drawRect(r, paint); 362 } 363 } 364 365private: 366 typedef Benchmark INHERITED; 367}; 368 369DEF_BENCH( return new Gradient2Bench(false); ) 370DEF_BENCH( return new Gradient2Bench(true); ) 371