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