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