blob: 02df14825be6ff81977d41d05b45c9faeb8f143a [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[] = {
commit-bot@chromium.orgb6865392013-07-09 19:43:29 +000025 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK,
reed@google.com84e9c082011-04-13 17:44:24 +000026};
27
28static const GradData gGradData[] = {
29 { 2, gColors, NULL },
reed@google.com84e9c082011-04-13 17:44:24 +000030};
31
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000032/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000033static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000034 SkShader::TileMode tm, SkUnitMapper* mapper,
35 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000036 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,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000041 SkShader::TileMode tm, SkUnitMapper* mapper,
42 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000043 SkPoint center;
44 center.set(SkScalarAve(pts[0].fX, pts[1].fX),
45 SkScalarAve(pts[0].fY, pts[1].fY));
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000046 return SkGradientShader::CreateRadial(center, center.fX * scale,
47 data.fColors,
reed@google.com84e9c082011-04-13 17:44:24 +000048 data.fPos, data.fCount, tm, mapper);
49}
50
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000051/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000052static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000053 SkShader::TileMode tm, SkUnitMapper* mapper,
54 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000055 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
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000062/// Ignores scale
reed@google.com84e9c082011-04-13 17:44:24 +000063static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000064 SkShader::TileMode tm, SkUnitMapper* mapper,
65 float scale) {
reed@google.com84e9c082011-04-13 17:44:24 +000066 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(
reed@google.com258e0bf2012-06-07 14:18:34 +000072 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);
reed@google.com84e9c082011-04-13 17:44:24 +000089}
90
91typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
tomhudson@google.com5ea050f2011-09-26 15:03:55 +000092 SkShader::TileMode tm, SkUnitMapper* mapper,
93 float scale);
reed@google.com84e9c082011-04-13 17:44:24 +000094
95static const struct {
96 GradMaker fMaker;
97 const char* fName;
98 int fRepeat;
99} gGrads[] = {
100 { MakeLinear, "linear", 15 },
reed@google.com80adceb2011-04-13 18:32:19 +0000101 { MakeRadial, "radial1", 10 },
reed@google.com84e9c082011-04-13 17:44:24 +0000102 { MakeSweep, "sweep", 1 },
103 { Make2Radial, "radial2", 5 },
reed@google.com258e0bf2012-06-07 14:18:34 +0000104 { MakeConical, "conical", 5 },
reed@google.com84e9c082011-04-13 17:44:24 +0000105};
106
107enum GradType { // these must match the order in gGrads
108 kLinear_GradType,
109 kRadial_GradType,
110 kSweep_GradType,
reed@google.com258e0bf2012-06-07 14:18:34 +0000111 kRadial2_GradType,
112 kConical_GradType
reed@google.com84e9c082011-04-13 17:44:24 +0000113};
114
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000115enum GeomType {
116 kRect_GeomType,
117 kOval_GeomType
118};
119
reed@google.com72415162011-06-15 21:17:37 +0000120static 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
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000134static 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
reed@google.com84e9c082011-04-13 17:44:24 +0000146///////////////////////////////////////////////////////////////////////////////
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:
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000158 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 }
reed@google.com84e9c082011-04-13 17:44:24 +0000169
170 const SkPoint pts[2] = {
171 { 0, 0 },
172 { SkIntToScalar(W), SkIntToScalar(H) }
173 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000174
tomhudson@google.comca529d32011-10-28 15:34:49 +0000175 fCount = SkBENCHLOOP(N * gGrads[gradType].fRepeat);
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000176 fShader = gGrads[gradType].fMaker(pts, gGradData[0], tm, NULL, scale);
177 fGeomType = geomType;
reed@google.com84e9c082011-04-13 17:44:24 +0000178 }
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++) {
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000197 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 }
reed@google.com84e9c082011-04-13 17:44:24 +0000205 }
206 }
207
208private:
209 typedef SkBenchmark INHERITED;
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000210
211 GeomType fGeomType;
reed@google.com84e9c082011-04-13 17:44:24 +0000212};
213
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000214class Gradient2Bench : public SkBenchmark {
reed@google.com73349aa2013-02-04 18:09:58 +0000215 SkString fName;
216 bool fHasAlpha;
217
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000218public:
reed@google.com73349aa2013-02-04 18:09:58 +0000219 Gradient2Bench(void* param, bool hasAlpha) : INHERITED(param) {
220 fName.printf("gradient_create_%s", hasAlpha ? "alpha" : "opaque");
221 fHasAlpha = hasAlpha;
222 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000223
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000224protected:
225 virtual const char* onGetName() {
reed@google.com73349aa2013-02-04 18:09:58 +0000226 return fName.c_str();
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000227 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000228
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000229 virtual void onDraw(SkCanvas* canvas) {
230 SkPaint paint;
231 this->setupPaint(&paint);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000232
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000233 const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
reed@google.com1ca4f262011-06-24 19:17:37 +0000234 const SkPoint pts[] = {
235 { 0, 0 },
236 { SkIntToScalar(100), SkIntToScalar(100) },
237 };
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000238
tomhudson@google.comca529d32011-10-28 15:34:49 +0000239 for (int i = 0; i < SkBENCHLOOP(1000); i++) {
reed@google.com73349aa2013-02-04 18:09:58 +0000240 const int gray = i % 256;
241 const int alpha = fHasAlpha ? gray : 0xFF;
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000242 SkColor colors[] = {
243 SK_ColorBLACK,
reed@google.com73349aa2013-02-04 18:09:58 +0000244 SkColorSetARGB(alpha, gray, gray, gray),
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000245 SK_ColorWHITE };
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000246 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 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000253
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000254private:
255 typedef SkBenchmark INHERITED;
256};
257
reed@google.com58ba4102013-02-04 18:00:54 +0000258DEF_BENCH( return new GradientBench(p, kLinear_GradType); )
259DEF_BENCH( return new GradientBench(p, kLinear_GradType, SkShader::kMirror_TileMode); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000260
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
reed@google.com58ba4102013-02-04 18:00:54 +0000263DEF_BENCH( return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000264
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)
reed@google.com58ba4102013-02-04 18:00:54 +0000267DEF_BENCH( return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kOval_GeomType); )
tomhudson@google.com5ea050f2011-09-26 15:03:55 +0000268
reed@google.com58ba4102013-02-04 18:00:54 +0000269DEF_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); )
reed@google.com8ac7a0f2011-06-16 13:14:19 +0000274
reed@google.com73349aa2013-02-04 18:09:58 +0000275DEF_BENCH( return new Gradient2Bench(p, false); )
276DEF_BENCH( return new Gradient2Bench(p, true); )