blob: 5ec9d8784eb8d98dab7669bb744a4bc5a46dd05b [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;
112 int fRepeat;
113} gGrads[] = {
114 { MakeLinear, "linear", 15 },
reed@google.com80adceb2011-04-13 18:32:19 +0000115 { MakeRadial, "radial1", 10 },
reed@google.com84e9c082011-04-13 17:44:24 +0000116 { MakeSweep, "sweep", 1 },
117 { Make2Radial, "radial2", 5 },
reed@google.com258e0bf2012-06-07 14:18:34 +0000118 { MakeConical, "conical", 5 },
reed@google.com84e9c082011-04-13 17:44:24 +0000119};
120
121enum GradType { // these must match the order in gGrads
122 kLinear_GradType,
123 kRadial_GradType,
124 kSweep_GradType,
reed@google.com258e0bf2012-06-07 14:18:34 +0000125 kRadial2_GradType,
126 kConical_GradType
reed@google.com84e9c082011-04-13 17:44:24 +0000127};
128
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000129enum GeomType {
130 kRect_GeomType,
131 kOval_GeomType
132};
133
reed@google.com72415162011-06-15 21:17:37 +0000134static const char* tilemodename(SkShader::TileMode tm) {
135 switch (tm) {
136 case SkShader::kClamp_TileMode:
137 return "clamp";
138 case SkShader::kRepeat_TileMode:
139 return "repeat";
140 case SkShader::kMirror_TileMode:
141 return "mirror";
142 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000143 SkDEBUGFAIL("unknown tilemode");
reed@google.com72415162011-06-15 21:17:37 +0000144 return "error";
145 }
146}
147
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000148static const char* geomtypename(GeomType gt) {
149 switch (gt) {
150 case kRect_GeomType:
151 return "rectangle";
152 case kOval_GeomType:
153 return "oval";
154 default:
mtklein@google.com330313a2013-08-22 15:37:26 +0000155 SkDEBUGFAIL("unknown geometry type");
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000156 return "error";
157 }
158}
159
reed@google.com84e9c082011-04-13 17:44:24 +0000160///////////////////////////////////////////////////////////////////////////////
161
162class GradientBench : public SkBenchmark {
163 SkString fName;
164 SkShader* fShader;
mtklein@google.comc2897432013-09-10 19:23:38 +0000165 int fRepeat;
reed@google.com84e9c082011-04-13 17:44:24 +0000166 enum {
167 W = 400,
168 H = 400,
reed@google.com84e9c082011-04-13 17:44:24 +0000169 };
170public:
mtklein@google.com410e6e82013-09-13 19:52:27 +0000171 GradientBench(GradType gradType,
commit-bot@chromium.org5396a042013-07-10 16:13:14 +0000172 GradData data = gGradData[0],
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000173 SkShader::TileMode tm = SkShader::kClamp_TileMode,
174 GeomType geomType = kRect_GeomType,
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +0000175 float scale = 1.0f) {
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000176 fName.printf("gradient_%s_%s", gGrads[gradType].fName,
177 tilemodename(tm));
178 if (geomType != kRect_GeomType) {
179 fName.append("_");
180 fName.append(geomtypename(geomType));
181 }
reed@google.com84e9c082011-04-13 17:44:24 +0000182
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +0000183 if (scale != 1.f) {
184 fName.appendf("_scale_%g", scale);
185 }
186
commit-bot@chromium.org5396a042013-07-10 16:13:14 +0000187 fName.append(data.fName);
188
reed@google.com84e9c082011-04-13 17:44:24 +0000189 const SkPoint pts[2] = {
190 { 0, 0 },
191 { SkIntToScalar(W), SkIntToScalar(H) }
192 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000193
mtklein@google.comc2897432013-09-10 19:23:38 +0000194 fRepeat = gGrads[gradType].fRepeat;
commit-bot@chromium.org5396a042013-07-10 16:13:14 +0000195 fShader = gGrads[gradType].fMaker(pts, data, tm, NULL, scale);
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000196 fGeomType = geomType;
reed@google.com84e9c082011-04-13 17:44:24 +0000197 }
198
199 virtual ~GradientBench() {
200 fShader->unref();
201 }
202
203protected:
204 virtual const char* onGetName() {
205 return fName.c_str();
206 }
207
208 virtual void onDraw(SkCanvas* canvas) {
209 SkPaint paint;
210 this->setupPaint(&paint);
211
212 paint.setShader(fShader);
213
214 SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
mtklein@google.comc2897432013-09-10 19:23:38 +0000215 for (int i = 0; i < this->getLoops() * fRepeat; i++) {
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000216 switch (fGeomType) {
217 case kRect_GeomType:
218 canvas->drawRect(r, paint);
219 break;
220 case kOval_GeomType:
221 canvas->drawOval(r, paint);
222 break;
223 }
reed@google.com84e9c082011-04-13 17:44:24 +0000224 }
225 }
226
227private:
228 typedef SkBenchmark INHERITED;
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000229
230 GeomType fGeomType;
reed@google.com84e9c082011-04-13 17:44:24 +0000231};
232
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000233class Gradient2Bench : public SkBenchmark {
reed@google.com73349aa2013-02-04 18:09:58 +0000234 SkString fName;
235 bool fHasAlpha;
236
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000237public:
mtklein@google.com410e6e82013-09-13 19:52:27 +0000238 Gradient2Bench(bool hasAlpha) {
reed@google.com73349aa2013-02-04 18:09:58 +0000239 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque");
240 fHasAlpha = hasAlpha;
241 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000242
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000243protected:
244 virtual const char* onGetName() {
reed@google.com73349aa2013-02-04 18:09:58 +0000245 return fName.c_str();
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000246 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000247
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000248 virtual void onDraw(SkCanvas* canvas) {
249 SkPaint paint;
250 this->setupPaint(&paint);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000251
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000252 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
reed@google.com1ca4f262011-06-24 19:17:37 +0000253 const SkPoint pts[] = {
254 { 0, 0 },
255 { SkIntToScalar(100), SkIntToScalar(100) },
256 };
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000257
mtklein@google.comc2897432013-09-10 19:23:38 +0000258 for (int i = 0; i < this->getLoops(); i++) {
reed@google.com73349aa2013-02-04 18:09:58 +0000259 const int gray = i % 256;
260 const int alpha = fHasAlpha ? gray : 0xFF;
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000261 SkColor colors[] = {
262 SK_ColorBLACK,
reed@google.com73349aa2013-02-04 18:09:58 +0000263 SkColorSetARGB(alpha, gray, gray, gray),
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000264 SK_ColorWHITE };
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000265 SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL,
266 SK_ARRAY_COUNT(colors),
267 SkShader::kClamp_TileMode);
268 paint.setShader(s)->unref();
269 canvas->drawRect(r, paint);
270 }
271 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000272
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000273private:
274 typedef SkBenchmark INHERITED;
275};
276
mtklein@google.com410e6e82013-09-13 19:52:27 +0000277DEF_BENCH( return new GradientBench(kLinear_GradType); )
278DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[1]); )
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +0000279DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[2]); )
mtklein@google.com410e6e82013-09-13 19:52:27 +0000280DEF_BENCH( return new GradientBench(kLinear_GradType, gGradData[0], SkShader::kMirror_TileMode); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000281
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +0000282
283DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0]); )
284DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[1]); )
285DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[2]); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000286// Draw a radial gradient of radius 1/2 on a rectangle; half the lines should
287// be completely pinned, the other half should pe partially pinned
mtklein@google.com410e6e82013-09-13 19:52:27 +0000288DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000289
290// Draw a radial gradient on a circle of equal size; all the lines should
291// hit the unpinned fast path (so long as GradientBench.W == H)
mtklein@google.com410e6e82013-09-13 19:52:27 +0000292DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kClamp_TileMode, kOval_GeomType); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000293
mtklein@google.com410e6e82013-09-13 19:52:27 +0000294DEF_BENCH( return new GradientBench(kRadial_GradType, gGradData[0], SkShader::kMirror_TileMode); )
295DEF_BENCH( return new GradientBench(kSweep_GradType); )
296DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[1]); )
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +0000297DEF_BENCH( return new GradientBench(kSweep_GradType, gGradData[2]); )
mtklein@google.com410e6e82013-09-13 19:52:27 +0000298DEF_BENCH( return new GradientBench(kRadial2_GradType); )
299DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[1]); )
300DEF_BENCH( return new GradientBench(kRadial2_GradType, gGradData[0], SkShader::kMirror_TileMode); )
301DEF_BENCH( return new GradientBench(kConical_GradType); )
302DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[1]); )
commit-bot@chromium.org3400f4b2013-09-30 19:41:09 +0000303DEF_BENCH( return new GradientBench(kConical_GradType, gGradData[2]); )
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000304
mtklein@google.com410e6e82013-09-13 19:52:27 +0000305DEF_BENCH( return new Gradient2Bench(false); )
306DEF_BENCH( return new Gradient2Bench(true); )