blob: e04a8122d13baee1f6e7edbbb204d0adea7790d9 [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;
commit-bot@chromium.org5396a042013-07-10 16:13:14 +000022 const char* fName;
reed@google.com84e9c082011-04-13 17:44:24 +000023};
24
25static const SkColor gColors[] = {
commit-bot@chromium.orgb6865392013-07-09 19:43:29 +000026 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
commit-bot@chromium.org5396a042013-07-10 16:13:14 +000027 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
reed@google.com84e9c082011-04-13 17:44:24 +000036};
37
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +000038// We have several special-cases depending on the number (and spacing) of colors, so
39// try to exercise those here.
reed@google.com84e9c082011-04-13 17:44:24 +000040static const GradData gGradData[] = {
commit-bot@chromium.org5396a042013-07-10 16:13:14 +000041 { 2, gColors, NULL, "" },
42 { 50, gColors, NULL, "_hicolor" }, // many color gradient
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +000043 { 3, gColors, NULL, "_3color" },
reed@google.com84e9c082011-04-13 17:44:24 +000044};
45
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000046/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000047static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000048 SkShader::TileMode tm, SkUnitMapper* mapper,
49 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000050 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,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000055 SkShader::TileMode tm, SkUnitMapper* mapper,
56 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000057 SkPoint center;
58 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
59 SkScalarAve(pts[0].fY, pts[1].fY));
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000060 return SkGradientShader::CreateRadial(center, center.fX * scale,
61 data.fColors,
reed@google.com84e9c082011-04-13 17:44:24 +000062 data.fPos, data.fCount, tm, mapper);
63}
64
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000065/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000066static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000067 SkShader::TileMode tm, SkUnitMapper* mapper,
68 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000069 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
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000076/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000077static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000078 SkShader::TileMode tm, SkUnitMapper* mapper,
79 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000080 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(
reed@google.com258e0bf2012-06-07 14:18:34 +000086 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);
reed@google.com84e9c082011-04-13 17:44:24 +0000103}
104
105typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000106 SkShader::TileMode tm, SkUnitMapper* mapper,
107 float scale);
reed@google.com84e9c082011-04-13 17:44:24 +0000108
109static const struct {
110 GradMaker fMaker;
111 const char* fName;
reed@google.com84e9c082011-04-13 17:44:24 +0000112} gGrads[] = {
commit-bot@chromium.orgb120bd92013-10-07 17:18:21 +0000113 { MakeLinear, "linear" },
114 { MakeRadial, "radial1" },
115 { MakeSweep, "sweep" },
116 { Make2Radial, "radial2" },
117 { MakeConical, "conical" },
reed@google.com84e9c082011-04-13 17:44:24 +0000118};
119
120enum GradType { // these must match the order in gGrads
121 kLinear_GradType,
122 kRadial_GradType,
123 kSweep_GradType,
reed@google.com258e0bf2012-06-07 14:18:34 +0000124 kRadial2_GradType,
125 kConical_GradType
reed@google.com84e9c082011-04-13 17:44:24 +0000126};
127
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000128enum GeomType {
129 kRect_GeomType,
130 kOval_GeomType
131};
132
reed@google.com72415162011-06-15 21:17:37 +0000133static 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:
mtklein@google.com330313a2013-08-22 15:37:26 +0000142 SkDEBUGFAIL("unknown tilemode");
reed@google.com72415162011-06-15 21:17:37 +0000143 return "error";
144 }
145}
146
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000147static const char* geomtypename(GeomType gt) {
148 switch (gt) {
149 case kRect_GeomType:
150 return "rectangle";
151 case kOval_GeomType:
152 return "oval";
153 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000154 SkDEBUGFAIL("unknown geometry type");
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000155 return "error";
156 }
157}
158
reed@google.com84e9c082011-04-13 17:44:24 +0000159///////////////////////////////////////////////////////////////////////////////
160
161class GradientBench : public SkBenchmark {
162 SkString fName;
163 SkShader* fShader;
reed@google.com84e9c082011-04-13 17:44:24 +0000164 enum {
165 W = 400,
166 H = 400,
commit-bot@chromium.orgb120bd92013-10-07 17:18:21 +0000167 kRepeat = 15,
reed@google.com84e9c082011-04-13 17:44:24 +0000168 };
169public:
mtklein@google.com410e6e82013-09-13 19:52:27 +0000170 GradientBench(GradType gradType,
commit-bot@chromium.org5396a042013-07-10 16:13:14 +0000171 GradData data = gGradData[0],
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000172 SkShader::TileMode tm = SkShader::kClamp_TileMode,
173 GeomType geomType = kRect_GeomType,
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +0000174 float scale = 1.0f) {
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000175 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 }
reed@google.com84e9c082011-04-13 17:44:24 +0000181
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +0000182 if (scale != 1.f) {
183 fName.appendf("_scale_%g", scale);
184 }
185
commit-bot@chromium.org5396a042013-07-10 16:13:14 +0000186 fName.append(data.fName);
187
reed@google.com84e9c082011-04-13 17:44:24 +0000188 const SkPoint pts[2] = {
189 { 0, 0 },
190 { SkIntToScalar(W), SkIntToScalar(H) }
191 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000192
commit-bot@chromium.org5396a042013-07-10 16:13:14 +0000193 fShader = gGrads[gradType].fMaker(pts, data, tm, NULL, scale);
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000194 fGeomType = geomType;
reed@google.com84e9c082011-04-13 17:44:24 +0000195 }
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(SkCanvas* canvas) {
207 SkPaint paint;
208 this->setupPaint(&paint);
209
210 paint.setShader(fShader);
211
212 SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
commit-bot@chromium.orgb120bd92013-10-07 17:18:21 +0000213 for (int i = 0; i < this->getLoops() * kRepeat; i++) {
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000214 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 }
reed@google.com84e9c082011-04-13 17:44:24 +0000222 }
223 }
224
225private:
226 typedef SkBenchmark INHERITED;
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000227
228 GeomType fGeomType;
reed@google.com84e9c082011-04-13 17:44:24 +0000229};
230
commit-bot@chromium.orgb120bd92013-10-07 17:18:21 +0000231DEF_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(kSweep_GradType); )
249DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); )
250DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); )
251DEF_BENCH( return new GradientBench(kRadial2_GradType); )
252DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[1]); )
253DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[0], SkShader::kMirror_TileMode); )
254DEF_BENCH( return new GradientBench(kConical_GradType); )
255DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); )
256DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); )
257
258///////////////////////////////////////////////////////////////////////////////
259
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000260class Gradient2Bench : public SkBenchmark {
reed@google.com73349aa2013-02-04 18:09:58 +0000261 SkString fName;
262 bool fHasAlpha;
263
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000264public:
mtklein@google.com410e6e82013-09-13 19:52:27 +0000265 Gradient2Bench(bool hasAlpha) {
reed@google.com73349aa2013-02-04 18:09:58 +0000266 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque");
267 fHasAlpha = hasAlpha;
268 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000269
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000270protected:
271 virtual const char* onGetName() {
reed@google.com73349aa2013-02-04 18:09:58 +0000272 return fName.c_str();
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000273 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000274
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000275 virtual void onDraw(SkCanvas* canvas) {
276 SkPaint paint;
277 this->setupPaint(&paint);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000278
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000279 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
reed@google.com1ca4f262011-06-24 19:17:37 +0000280 const SkPoint pts[] = {
281 { 0, 0 },
282 { SkIntToScalar(100), SkIntToScalar(100) },
283 };
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000284
mtklein@google.comc2897432013-09-10 19:23:38 +0000285 for (int i = 0; i < this->getLoops(); i++) {
reed@google.com73349aa2013-02-04 18:09:58 +0000286 const int gray = i % 256;
287 const int alpha = fHasAlpha ? gray : 0xFF;
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000288 SkColor colors[] = {
289 SK_ColorBLACK,
reed@google.com73349aa2013-02-04 18:09:58 +0000290 SkColorSetARGB(alpha, gray, gray, gray),
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000291 SK_ColorWHITE };
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000292 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL,
293 SK_ARRAY_COUNT(colors),
294 SkShader::kClamp_TileMode);
295 paint.setShader(s)->unref();
296 canvas->drawRect(r, paint);
297 }
298 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000299
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000300private:
301 typedef SkBenchmark INHERITED;
302};
303
mtklein@google.com410e6e82013-09-13 19:52:27 +0000304DEF_BENCH( return new Gradient2Bench(false); )
305DEF_BENCH( return new Gradient2Bench(true); )