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