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