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 "SkLinearGradient.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, nullptr, "" }, 43 { 50, gColors, nullptr, "_hicolor" }, // many color gradient 44 { 3, gColors, nullptr, "_3color" }, 45 { 2, gShallowColors, nullptr, "_shallow" }, 46 }; 47 48 /// Ignores scale 49 static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data, 50 SkShader::TileMode tm, float scale, bool force4f) { 51 const uint32_t flags = force4f ? SkLinearGradient::kForce4fContext_PrivateFlag : 0; 52 return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, 53 data.fCount, tm, flags, nullptr); 54 } 55 56 static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data, 57 SkShader::TileMode tm, float scale, bool force4f) { 58 SkPoint center; 59 center.set(SkScalarAve(pts[0].fX, pts[1].fX), 60 SkScalarAve(pts[0].fY, pts[1].fY)); 61 return SkGradientShader::MakeRadial(center, center.fX * scale, data.fColors, 62 data.fPos, data.fCount, tm); 63 } 64 65 /// Ignores scale 66 static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data, 67 SkShader::TileMode tm, float scale, bool force4f) { 68 SkPoint center; 69 center.set(SkScalarAve(pts[0].fX, pts[1].fX), 70 SkScalarAve(pts[0].fY, pts[1].fY)); 71 return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount); 72 } 73 74 /// Ignores scale 75 static sk_sp<SkShader> MakeConical(const SkPoint pts[2], const GradData& data, 76 SkShader::TileMode tm, float scale, bool force4f) { 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::MakeTwoPointConical(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 88 static sk_sp<SkShader> MakeConicalZeroRad(const SkPoint pts[2], const GradData& data, 89 SkShader::TileMode tm, float scale, bool force4f) { 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::MakeTwoPointConical(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 101 static sk_sp<SkShader> MakeConicalOutside(const SkPoint pts[2], const GradData& data, 102 SkShader::TileMode tm, float scale, bool force4f) { 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::MakeTwoPointConical(center0, radius0, 109 center1, radius1, 110 data.fColors, data.fPos, 111 data.fCount, tm); 112 } 113 114 /// Ignores scale 115 static sk_sp<SkShader> MakeConicalOutsideZeroRad(const SkPoint pts[2], const GradData& data, 116 SkShader::TileMode tm, float scale, bool force4f) { 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::MakeTwoPointConical(center0, 0.0, 123 center1, radius1, 124 data.fColors, data.fPos, 125 data.fCount, tm); 126 } 127 128 typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, 129 SkShader::TileMode tm, float scale, bool force4f); 130 131 static 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 144 enum 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 154 enum GeomType { 155 kRect_GeomType, 156 kOval_GeomType 157 }; 158 159 static 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 173 static 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 187 class GradientBench : public Benchmark { 188 public: 189 GradientBench(GradType gradType, 190 GradData data = gGradData[0], 191 SkShader::TileMode tm = SkShader::kClamp_TileMode, 192 GeomType geomType = kRect_GeomType, 193 float scale = 1.0f, 194 bool force4f = false) 195 : fGeomType(geomType) { 196 197 fName.printf("gradient_%s_%s", gGrads[gradType].fName, 198 tilemodename(tm)); 199 if (geomType != kRect_GeomType) { 200 fName.appendf("_%s", geomtypename(geomType)); 201 } 202 203 if (scale != 1.f) { 204 fName.appendf("_scale_%g", scale); 205 } 206 207 fName.append(data.fName); 208 209 if (force4f) { 210 fName.append("_4f"); 211 } 212 213 this->setupPaint(&fPaint); 214 fPaint.setShader(MakeShader(gradType, data, tm, scale, force4f)); 215 } 216 217 GradientBench(GradType gradType, GradData data, bool dither, bool force4f = false) 218 : fGeomType(kRect_GeomType) { 219 220 const char *tmname = tilemodename(SkShader::kClamp_TileMode); 221 fName.printf("gradient_%s_%s", gGrads[gradType].fName, tmname); 222 fName.append(data.fName); 223 224 if (dither) { 225 fName.appendf("_dither"); 226 } 227 228 this->setupPaint(&fPaint); 229 fPaint.setShader(MakeShader(gradType, data, SkShader::kClamp_TileMode, 1.0f, force4f)); 230 fPaint.setDither(dither); 231 } 232 233 protected: 234 const char* onGetName() override { 235 return fName.c_str(); 236 } 237 238 SkIPoint onGetSize() override { 239 return SkIPoint::Make(kSize, kSize); 240 } 241 242 void onDraw(int loops, SkCanvas* canvas) override { 243 const SkRect r = SkRect::MakeIWH(kSize, kSize); 244 245 for (int i = 0; i < loops; i++) { 246 switch (fGeomType) { 247 case kRect_GeomType: 248 canvas->drawRect(r, fPaint); 249 break; 250 case kOval_GeomType: 251 canvas->drawOval(r, fPaint); 252 break; 253 } 254 } 255 } 256 257 private: 258 typedef Benchmark INHERITED; 259 260 sk_sp<SkShader> MakeShader(GradType gradType, GradData data, 261 SkShader::TileMode tm, float scale, bool force4f) { 262 const SkPoint pts[2] = { 263 { 0, 0 }, 264 { SkIntToScalar(kSize), SkIntToScalar(kSize) } 265 }; 266 267 return gGrads[gradType].fMaker(pts, data, tm, scale, force4f); 268 } 269 270 static const int kSize = 400; 271 272 SkString fName; 273 SkPaint fPaint; 274 const GeomType fGeomType; 275 }; 276 277 // 4f 278 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kClamp_TileMode, 279 kRect_GeomType, 1, true); ) 280 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1], SkShader::kClamp_TileMode, 281 kRect_GeomType, 1, true); ) 282 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2], SkShader::kClamp_TileMode, 283 kRect_GeomType, 1, true); ) 284 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kRepeat_TileMode, 285 kRect_GeomType, 1, true); ) 286 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1], SkShader::kRepeat_TileMode, 287 kRect_GeomType, 1, true); ) 288 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2], SkShader::kRepeat_TileMode, 289 kRect_GeomType, 1, true); ) 290 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode, 291 kRect_GeomType, 1, true); ) 292 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1], SkShader::kMirror_TileMode, 293 kRect_GeomType, 1, true); ) 294 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2], SkShader::kMirror_TileMode, 295 kRect_GeomType, 1, true); ) 296 297 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0]); ) 298 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1]); ) 299 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2]); ) 300 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kRepeat_TileMode); ) 301 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1], SkShader::kRepeat_TileMode); ) 302 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2], SkShader::kRepeat_TileMode); ) 303 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 304 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1], SkShader::kMirror_TileMode); ) 305 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2], SkShader::kMirror_TileMode); ) 306 307 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0]); ) 308 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[1]); ) 309 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[2]); ) 310 // Draw a radial gradient of radius 1/2 on a rectangle; half the lines should 311 // be completely pinned, the other half should pe partially pinned 312 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); ) 313 314 // Draw a radial gradient on a circle of equal size; all the lines should 315 // hit the unpinned fast path (so long as GradientBench.W == H) 316 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kOval_GeomType); ) 317 318 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 319 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kRepeat_TileMode); ) 320 DEF_BENCH( return new GradientBench(kSweep_GradType); ) 321 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); ) 322 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); ) 323 DEF_BENCH( return new GradientBench(kConical_GradType); ) 324 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); ) 325 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); ) 326 DEF_BENCH( return new GradientBench(kConicalZero_GradType); ) 327 DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[1]); ) 328 DEF_BENCH( return new GradientBench(kConicalZero_GradType, gGradData[2]); ) 329 DEF_BENCH( return new GradientBench(kConicalOut_GradType); ) 330 DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[1]); ) 331 DEF_BENCH( return new GradientBench(kConicalOut_GradType, gGradData[2]); ) 332 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType); ) 333 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[1]); ) 334 DEF_BENCH( return new GradientBench(kConicalOutZero_GradType, gGradData[2]); ) 335 336 // Dithering 337 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], true); ) 338 DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[3], false); ) 339 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], true); ) 340 DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[3], false); ) 341 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], true); ) 342 DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[3], false); ) 343 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], true); ) 344 DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[3], false); ) 345 346 /////////////////////////////////////////////////////////////////////////////// 347 348 class Gradient2Bench : public Benchmark { 349 SkString fName; 350 bool fHasAlpha; 351 352 public: 353 Gradient2Bench(bool hasAlpha) { 354 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque"); 355 fHasAlpha = hasAlpha; 356 } 357 358 protected: 359 virtual const char* onGetName() { 360 return fName.c_str(); 361 } 362 363 virtual void onDraw(int loops, SkCanvas* canvas) { 364 SkPaint paint; 365 this->setupPaint(&paint); 366 367 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) }; 368 const SkPoint pts[] = { 369 { 0, 0 }, 370 { SkIntToScalar(100), SkIntToScalar(100) }, 371 }; 372 373 for (int i = 0; i < loops; i++) { 374 const int gray = i % 256; 375 const int alpha = fHasAlpha ? gray : 0xFF; 376 SkColor colors[] = { 377 SK_ColorBLACK, 378 SkColorSetARGB(alpha, gray, gray, gray), 379 SK_ColorWHITE }; 380 paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 381 SK_ARRAY_COUNT(colors), 382 SkShader::kClamp_TileMode)); 383 canvas->drawRect(r, paint); 384 } 385 } 386 387 private: 388 typedef Benchmark INHERITED; 389 }; 390 391 DEF_BENCH( return new Gradient2Bench(false); ) 392 DEF_BENCH( return new Gradient2Bench(true); ) 393