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 "SkBenchmark.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 #include "SkUnitMapper.h" 17 18 struct GradData { 19 int fCount; 20 const SkColor* fColors; 21 const SkScalar* fPos; 22 const char* fName; 23 }; 24 25 static const SkColor gColors[] = { 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, 35 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK, // 10 lines, 50 colors 36 }; 37 38 static const GradData gGradData[] = { 39 { 2, gColors, NULL, "" }, 40 { 50, gColors, NULL, "_hicolor" }, // many color gradient 41 }; 42 43 /// Ignores scale 44 static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data, 45 SkShader::TileMode tm, SkUnitMapper* mapper, 46 float scale) { 47 return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos, 48 data.fCount, tm, mapper); 49 } 50 51 static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data, 52 SkShader::TileMode tm, SkUnitMapper* mapper, 53 float scale) { 54 SkPoint center; 55 center.set(SkScalarAve(pts[0].fX, pts[1].fX), 56 SkScalarAve(pts[0].fY, pts[1].fY)); 57 return SkGradientShader::CreateRadial(center, center.fX * scale, 58 data.fColors, 59 data.fPos, data.fCount, tm, mapper); 60 } 61 62 /// Ignores scale 63 static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data, 64 SkShader::TileMode tm, SkUnitMapper* mapper, 65 float scale) { 66 SkPoint center; 67 center.set(SkScalarAve(pts[0].fX, pts[1].fX), 68 SkScalarAve(pts[0].fY, pts[1].fY)); 69 return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors, 70 data.fPos, data.fCount, mapper); 71 } 72 73 /// Ignores scale 74 static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data, 75 SkShader::TileMode tm, SkUnitMapper* mapper, 76 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, mapper); 86 } 87 88 /// Ignores scale 89 static SkShader* MakeConical(const SkPoint pts[2], const GradData& data, 90 SkShader::TileMode tm, SkUnitMapper* mapper, 91 float scale) { 92 SkPoint center0, center1; 93 center0.set(SkScalarAve(pts[0].fX, pts[1].fX), 94 SkScalarAve(pts[0].fY, pts[1].fY)); 95 center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5), 96 SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4)); 97 return SkGradientShader::CreateTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7, 98 center0, (pts[1].fX - pts[0].fX) / 2, 99 data.fColors, data.fPos, data.fCount, tm, mapper); 100 } 101 102 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, 103 SkShader::TileMode tm, SkUnitMapper* mapper, 104 float scale); 105 106 static const struct { 107 GradMaker fMaker; 108 const char* fName; 109 int fRepeat; 110 } gGrads[] = { 111 { MakeLinear, "linear", 15 }, 112 { MakeRadial, "radial1", 10 }, 113 { MakeSweep, "sweep", 1 }, 114 { Make2Radial, "radial2", 5 }, 115 { MakeConical, "conical", 5 }, 116 }; 117 118 enum GradType { // these must match the order in gGrads 119 kLinear_GradType, 120 kRadial_GradType, 121 kSweep_GradType, 122 kRadial2_GradType, 123 kConical_GradType 124 }; 125 126 enum GeomType { 127 kRect_GeomType, 128 kOval_GeomType 129 }; 130 131 static const char* tilemodename(SkShader::TileMode tm) { 132 switch (tm) { 133 case SkShader::kClamp_TileMode: 134 return "clamp"; 135 case SkShader::kRepeat_TileMode: 136 return "repeat"; 137 case SkShader::kMirror_TileMode: 138 return "mirror"; 139 default: 140 SkASSERT(!"unknown tilemode"); 141 return "error"; 142 } 143 } 144 145 static const char* geomtypename(GeomType gt) { 146 switch (gt) { 147 case kRect_GeomType: 148 return "rectangle"; 149 case kOval_GeomType: 150 return "oval"; 151 default: 152 SkASSERT(!"unknown geometry type"); 153 return "error"; 154 } 155 } 156 157 /////////////////////////////////////////////////////////////////////////////// 158 159 class GradientBench : public SkBenchmark { 160 SkString fName; 161 SkShader* fShader; 162 int fCount; 163 enum { 164 W = 400, 165 H = 400, 166 N = 1 167 }; 168 public: 169 GradientBench(void* param, GradType gradType, 170 GradData data = gGradData[0], 171 SkShader::TileMode tm = SkShader::kClamp_TileMode, 172 GeomType geomType = kRect_GeomType, 173 float scale = 1.0f 174 ) 175 : INHERITED(param) { 176 fName.printf("gradient_%s_%s", gGrads[gradType].fName, 177 tilemodename(tm)); 178 if (geomType != kRect_GeomType) { 179 fName.append("_"); 180 fName.append(geomtypename(geomType)); 181 } 182 183 fName.append(data.fName); 184 185 const SkPoint pts[2] = { 186 { 0, 0 }, 187 { SkIntToScalar(W), SkIntToScalar(H) } 188 }; 189 190 fCount = SkBENCHLOOP(N * gGrads[gradType].fRepeat); 191 fShader = gGrads[gradType].fMaker(pts, data, tm, NULL, scale); 192 fGeomType = geomType; 193 } 194 195 virtual ~GradientBench() { 196 fShader->unref(); 197 } 198 199 protected: 200 virtual const char* onGetName() { 201 return fName.c_str(); 202 } 203 204 virtual void onDraw(SkCanvas* canvas) { 205 SkPaint paint; 206 this->setupPaint(&paint); 207 208 paint.setShader(fShader); 209 210 SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) }; 211 for (int i = 0; i < fCount; i++) { 212 switch (fGeomType) { 213 case kRect_GeomType: 214 canvas->drawRect(r, paint); 215 break; 216 case kOval_GeomType: 217 canvas->drawOval(r, paint); 218 break; 219 } 220 } 221 } 222 223 private: 224 typedef SkBenchmark INHERITED; 225 226 GeomType fGeomType; 227 }; 228 229 class Gradient2Bench : public SkBenchmark { 230 SkString fName; 231 bool fHasAlpha; 232 233 public: 234 Gradient2Bench(void* param, bool hasAlpha) : INHERITED(param) { 235 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque"); 236 fHasAlpha = hasAlpha; 237 } 238 239 protected: 240 virtual const char* onGetName() { 241 return fName.c_str(); 242 } 243 244 virtual void onDraw(SkCanvas* canvas) { 245 SkPaint paint; 246 this->setupPaint(&paint); 247 248 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) }; 249 const SkPoint pts[] = { 250 { 0, 0 }, 251 { SkIntToScalar(100), SkIntToScalar(100) }, 252 }; 253 254 for (int i = 0; i < SkBENCHLOOP(1000); i++) { 255 const int gray = i % 256; 256 const int alpha = fHasAlpha ? gray : 0xFF; 257 SkColor colors[] = { 258 SK_ColorBLACK, 259 SkColorSetARGB(alpha, gray, gray, gray), 260 SK_ColorWHITE }; 261 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 262 SK_ARRAY_COUNT(colors), 263 SkShader::kClamp_TileMode); 264 paint.setShader(s)->unref(); 265 canvas->drawRect(r, paint); 266 } 267 } 268 269 private: 270 typedef SkBenchmark INHERITED; 271 }; 272 273 DEF_BENCH( return new GradientBench(p, kLinear_GradType); ) 274 DEF_BENCH( return new GradientBench(p, kLinear_GradType, gGradData[1]); ) 275 DEF_BENCH( return new GradientBench(p, kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 276 277 // Draw a radial gradient of radius 1/2 on a rectangle; half the lines should 278 // be completely pinned, the other half should pe partially pinned 279 DEF_BENCH( return new GradientBench(p, kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); ) 280 281 // Draw a radial gradient on a circle of equal size; all the lines should 282 // hit the unpinned fast path (so long as GradientBench.W == H) 283 DEF_BENCH( return new GradientBench(p, kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kOval_GeomType); ) 284 285 DEF_BENCH( return new GradientBench(p, kRadial_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 286 DEF_BENCH( return new GradientBench(p, kSweep_GradType); ) 287 DEF_BENCH( return new GradientBench(p, kSweep_GradType, gGradData[1]); ) 288 DEF_BENCH( return new GradientBench(p, kRadial2_GradType); ) 289 DEF_BENCH( return new GradientBench(p, kRadial2_GradType, gGradData[1]); ) 290 DEF_BENCH( return new GradientBench(p, kRadial2_GradType, gGradData[0], SkShader::kMirror_TileMode); ) 291 DEF_BENCH( return new GradientBench(p, kConical_GradType); ) 292 DEF_BENCH( return new GradientBench(p, kConical_GradType, gGradData[1]); ) 293 294 DEF_BENCH( return new Gradient2Bench(p, false); ) 295 DEF_BENCH( return new Gradient2Bench(p, true); ) 296