blob: 2787edbf0b21dbbcd8c2de7138d30107ea6359a3 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@google.com84e9c082011-04-13 17:44:24 +00008#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};
27static const SkScalar gPos0[] = { 0, SK_Scalar1 };
28static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
29static const SkScalar gPos2[] = {
30 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
31};
32
33static 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
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000041/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000042static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000043 SkShader::TileMode tm, SkUnitMapper* mapper,
44 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000045 return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
46 data.fCount, tm, mapper);
47}
48
49static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000050 SkShader::TileMode tm, SkUnitMapper* mapper,
51 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000052 SkPoint center;
53 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
54 SkScalarAve(pts[0].fY, pts[1].fY));
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000055 return SkGradientShader::CreateRadial(center, center.fX * scale,
56 data.fColors,
reed@google.com84e9c082011-04-13 17:44:24 +000057 data.fPos, data.fCount, tm, mapper);
58}
59
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000060/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000061static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000062 SkShader::TileMode tm, SkUnitMapper* mapper,
63 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000064 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
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000071/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000072static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000073 SkShader::TileMode tm, SkUnitMapper* mapper,
74 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000075 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(
reed@google.com258e0bf2012-06-07 14:18:34 +000081 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
87static 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);
reed@google.com84e9c082011-04-13 17:44:24 +000098}
99
100typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000101 SkShader::TileMode tm, SkUnitMapper* mapper,
102 float scale);
reed@google.com84e9c082011-04-13 17:44:24 +0000103
104static const struct {
105 GradMaker fMaker;
106 const char* fName;
107 int fRepeat;
108} gGrads[] = {
109 { MakeLinear, "linear", 15 },
reed@google.com80adceb2011-04-13 18:32:19 +0000110 { MakeRadial, "radial1", 10 },
reed@google.com84e9c082011-04-13 17:44:24 +0000111 { MakeSweep, "sweep", 1 },
112 { Make2Radial, "radial2", 5 },
reed@google.com258e0bf2012-06-07 14:18:34 +0000113 { MakeConical, "conical", 5 },
reed@google.com84e9c082011-04-13 17:44:24 +0000114};
115
116enum GradType { // these must match the order in gGrads
117 kLinear_GradType,
118 kRadial_GradType,
119 kSweep_GradType,
reed@google.com258e0bf2012-06-07 14:18:34 +0000120 kRadial2_GradType,
121 kConical_GradType
reed@google.com84e9c082011-04-13 17:44:24 +0000122};
123
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000124enum GeomType {
125 kRect_GeomType,
126 kOval_GeomType
127};
128
reed@google.com72415162011-06-15 21:17:37 +0000129static 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
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000143static 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
reed@google.com84e9c082011-04-13 17:44:24 +0000155///////////////////////////////////////////////////////////////////////////////
156
157class GradientBench : public SkBenchmark {
158 SkString fName;
159 SkShader* fShader;
160 int fCount;
161 enum {
162 W = 400,
163 H = 400,
164 N = 1
165 };
166public:
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000167 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 }
reed@google.com84e9c082011-04-13 17:44:24 +0000178
179 const SkPoint pts[2] = {
180 { 0, 0 },
181 { SkIntToScalar(W), SkIntToScalar(H) }
182 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000183
tomhudson@google.comca529d32011-10-28 15:34:49 +0000184 fCount = SkBENCHLOOP(N * gGrads[gradType].fRepeat);
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000185 fShader = gGrads[gradType].fMaker(pts, gGradData[0], tm, NULL, scale);
186 fGeomType = geomType;
reed@google.com84e9c082011-04-13 17:44:24 +0000187 }
188
189 virtual ~GradientBench() {
190 fShader->unref();
191 }
192
193protected:
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++) {
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000206 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 }
reed@google.com84e9c082011-04-13 17:44:24 +0000214 }
215 }
216
217private:
218 typedef SkBenchmark INHERITED;
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000219
220 GeomType fGeomType;
reed@google.com84e9c082011-04-13 17:44:24 +0000221};
222
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000223class Gradient2Bench : public SkBenchmark {
reed@google.com73349aa2013-02-04 18:09:58 +0000224 SkString fName;
225 bool fHasAlpha;
226
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000227public:
reed@google.com73349aa2013-02-04 18:09:58 +0000228 Gradient2Bench(void* param, bool hasAlpha) : INHERITED(param) {
229 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque");
230 fHasAlpha = hasAlpha;
231 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000232
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000233protected:
234 virtual const char* onGetName() {
reed@google.com73349aa2013-02-04 18:09:58 +0000235 return fName.c_str();
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000236 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000237
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000238 virtual void onDraw(SkCanvas* canvas) {
239 SkPaint paint;
240 this->setupPaint(&paint);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000241
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000242 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
reed@google.com1ca4f262011-06-24 19:17:37 +0000243 const SkPoint pts[] = {
244 { 0, 0 },
245 { SkIntToScalar(100), SkIntToScalar(100) },
246 };
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000247
tomhudson@google.comca529d32011-10-28 15:34:49 +0000248 for (int i = 0; i < SkBENCHLOOP(1000); i++) {
reed@google.com73349aa2013-02-04 18:09:58 +0000249 const int gray = i % 256;
250 const int alpha = fHasAlpha ? gray : 0xFF;
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000251 SkColor colors[] = {
252 SK_ColorBLACK,
reed@google.com73349aa2013-02-04 18:09:58 +0000253 SkColorSetARGB(alpha, gray, gray, gray),
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000254 SK_ColorWHITE };
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000255 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL,
256 SK_ARRAY_COUNT(colors),
257 SkShader::kClamp_TileMode);
258 paint.setShader(s)->unref();
259 canvas->drawRect(r, paint);
260 }
261 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000262
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000263private:
264 typedef SkBenchmark INHERITED;
265};
266
reed@google.com58ba4102013-02-04 18:00:54 +0000267DEF_BENCH( return new GradientBench(p, kLinear_GradType); )
268DEF_BENCH( return new GradientBench(p, kLinear_GradType, SkShader::kMirror_TileMode); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000269
270// Draw a radial gradient of radius 1/2 on a rectangle; half the lines should
271// be completely pinned, the other half should pe partially pinned
reed@google.com58ba4102013-02-04 18:00:54 +0000272DEF_BENCH( return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000273
274// Draw a radial gradient on a circle of equal size; all the lines should
275// hit the unpinned fast path (so long as GradientBench.W == H)
reed@google.com58ba4102013-02-04 18:00:54 +0000276DEF_BENCH( return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kOval_GeomType); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000277
reed@google.com58ba4102013-02-04 18:00:54 +0000278DEF_BENCH( return new GradientBench(p, kRadial_GradType, SkShader::kMirror_TileMode); )
279DEF_BENCH( return new GradientBench(p, kSweep_GradType); )
280DEF_BENCH( return new GradientBench(p, kRadial2_GradType); )
281DEF_BENCH( return new GradientBench(p, kRadial2_GradType, SkShader::kMirror_TileMode); )
282DEF_BENCH( return new GradientBench(p, kConical_GradType); )
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000283
reed@google.com73349aa2013-02-04 18:09:58 +0000284DEF_BENCH( return new Gradient2Bench(p, false); )
285DEF_BENCH( return new Gradient2Bench(p, true); )