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 typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data, 87 SkShader::TileMode tm, SkUnitMapper* mapper, 88 float scale); 89 90 static const struct { 91 GradMaker fMaker; 92 const char* fName; 93 int fRepeat; 94 } gGrads[] = { 95 { MakeLinear, "linear", 15 }, 96 { MakeRadial, "radial1", 10 }, 97 { MakeSweep, "sweep", 1 }, 98 { Make2Radial, "radial2", 5 }, 99 }; 100 101 enum GradType { // these must match the order in gGrads 102 kLinear_GradType, 103 kRadial_GradType, 104 kSweep_GradType, 105 kRadial2_GradType 106 }; 107 108 enum GeomType { 109 kRect_GeomType, 110 kOval_GeomType 111 }; 112 113 static const char* tilemodename(SkShader::TileMode tm) { 114 switch (tm) { 115 case SkShader::kClamp_TileMode: 116 return "clamp"; 117 case SkShader::kRepeat_TileMode: 118 return "repeat"; 119 case SkShader::kMirror_TileMode: 120 return "mirror"; 121 default: 122 SkASSERT(!"unknown tilemode"); 123 return "error"; 124 } 125 } 126 127 static const char* geomtypename(GeomType gt) { 128 switch (gt) { 129 case kRect_GeomType: 130 return "rectangle"; 131 case kOval_GeomType: 132 return "oval"; 133 default: 134 SkASSERT(!"unknown geometry type"); 135 return "error"; 136 } 137 } 138 139 /////////////////////////////////////////////////////////////////////////////// 140 141 class GradientBench : public SkBenchmark { 142 SkString fName; 143 SkShader* fShader; 144 int fCount; 145 enum { 146 W = 400, 147 H = 400, 148 N = 1 149 }; 150 public: 151 GradientBench(void* param, GradType gradType, 152 SkShader::TileMode tm = SkShader::kClamp_TileMode, 153 GeomType geomType = kRect_GeomType, 154 float scale = 1.0f) 155 : INHERITED(param) { 156 fName.printf("gradient_%s_%s", gGrads[gradType].fName, 157 tilemodename(tm)); 158 if (geomType != kRect_GeomType) { 159 fName.append("_"); 160 fName.append(geomtypename(geomType)); 161 } 162 163 const SkPoint pts[2] = { 164 { 0, 0 }, 165 { SkIntToScalar(W), SkIntToScalar(H) } 166 }; 167 168 fCount = SkBENCHLOOP(N * gGrads[gradType].fRepeat); 169 fShader = gGrads[gradType].fMaker(pts, gGradData[0], tm, NULL, scale); 170 fGeomType = geomType; 171 } 172 173 virtual ~GradientBench() { 174 fShader->unref(); 175 } 176 177 protected: 178 virtual const char* onGetName() { 179 return fName.c_str(); 180 } 181 182 virtual void onDraw(SkCanvas* canvas) { 183 SkPaint paint; 184 this->setupPaint(&paint); 185 186 paint.setShader(fShader); 187 188 SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) }; 189 for (int i = 0; i < fCount; i++) { 190 switch (fGeomType) { 191 case kRect_GeomType: 192 canvas->drawRect(r, paint); 193 break; 194 case kOval_GeomType: 195 canvas->drawOval(r, paint); 196 break; 197 } 198 } 199 } 200 201 private: 202 typedef SkBenchmark INHERITED; 203 204 GeomType fGeomType; 205 }; 206 207 class Gradient2Bench : public SkBenchmark { 208 public: 209 Gradient2Bench(void* param) : INHERITED(param) {} 210 211 protected: 212 virtual const char* onGetName() { 213 return "gradient_create"; 214 } 215 216 virtual void onDraw(SkCanvas* canvas) { 217 SkPaint paint; 218 this->setupPaint(&paint); 219 220 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) }; 221 const SkPoint pts[] = { 222 { 0, 0 }, 223 { SkIntToScalar(100), SkIntToScalar(100) }, 224 }; 225 226 for (int i = 0; i < SkBENCHLOOP(1000); i++) { 227 const int a = i % 256; 228 SkColor colors[] = { 229 SK_ColorBLACK, 230 SkColorSetARGB(a, a, a, a), 231 SK_ColorWHITE }; 232 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 233 SK_ARRAY_COUNT(colors), 234 SkShader::kClamp_TileMode); 235 paint.setShader(s)->unref(); 236 canvas->drawRect(r, paint); 237 } 238 } 239 240 private: 241 typedef SkBenchmark INHERITED; 242 }; 243 244 static SkBenchmark* Fact0(void* p) { return new GradientBench(p, kLinear_GradType); } 245 static SkBenchmark* Fact01(void* p) { return new GradientBench(p, kLinear_GradType, SkShader::kMirror_TileMode); } 246 247 // Draw a radial gradient of radius 1/2 on a rectangle; half the lines should 248 // be completely pinned, the other half should pe partially pinned 249 static SkBenchmark* Fact1(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); } 250 251 // Draw a radial gradient on a circle of equal size; all the lines should 252 // hit the unpinned fast path (so long as GradientBench.W == H) 253 static SkBenchmark* Fact1o(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kOval_GeomType); } 254 255 static SkBenchmark* Fact11(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kMirror_TileMode); } 256 static SkBenchmark* Fact2(void* p) { return new GradientBench(p, kSweep_GradType); } 257 static SkBenchmark* Fact3(void* p) { return new GradientBench(p, kRadial2_GradType); } 258 static SkBenchmark* Fact31(void* p) { return new GradientBench(p, kRadial2_GradType, SkShader::kMirror_TileMode); } 259 260 static SkBenchmark* Fact4(void* p) { return new Gradient2Bench(p); } 261 262 static BenchRegistry gReg0(Fact0); 263 static BenchRegistry gReg01(Fact01); 264 static BenchRegistry gReg1(Fact1); 265 static BenchRegistry gReg1o(Fact1o); 266 static BenchRegistry gReg11(Fact11); 267 static BenchRegistry gReg2(Fact2); 268 static BenchRegistry gReg3(Fact3); 269 static BenchRegistry gReg31(Fact31); 270 271 static BenchRegistry gReg4(Fact4); 272 273