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