DashBench.cpp revision fbfcd5602128ec010c82cb733c9cdc0a3254f9f3
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 "SkDashPathEffect.h"
12#include "SkPaint.h"
13#include "SkPath.h"
14#include "SkRandom.h"
15#include "SkString.h"
16#include "SkTDArray.h"
17
18
19/*
20 *  Cases to consider:
21 *
22 *  1. antialiasing on/off (esp. width <= 1)
23 *  2. strokewidth == 0, 1, 2
24 *  3. hline, vline, diagonal, rect, oval
25 *  4. dots [1,1] ([N,N] where N=strokeWidth?) or arbitrary (e.g. [2,1] or [1,2,3,2])
26 */
27static void path_hline(SkPath* path) {
28    path->moveTo(SkIntToScalar(10), SkIntToScalar(10));
29    path->lineTo(SkIntToScalar(600), SkIntToScalar(10));
30}
31
32class DashBench : public SkBenchmark {
33protected:
34    SkString            fName;
35    SkTDArray<SkScalar> fIntervals;
36    int                 fWidth;
37    SkPoint             fPts[2];
38    bool                fDoClip;
39
40    enum {
41        N = SkBENCHLOOP(100)
42    };
43public:
44    DashBench(void* param, const SkScalar intervals[], int count, int width,
45              bool doClip = false) : INHERITED(param) {
46        fIntervals.append(count, intervals);
47        for (int i = 0; i < count; ++i) {
48            fIntervals[i] *= width;
49        }
50        fWidth = width;
51        fName.printf("dash_%d_%s", width, doClip ? "clipped" : "noclip");
52        fDoClip = doClip;
53
54        fPts[0].set(SkIntToScalar(10), SkIntToScalar(10));
55        fPts[1].set(SkIntToScalar(600), SkIntToScalar(10));
56    }
57
58    virtual void makePath(SkPath* path) {
59        path_hline(path);
60    }
61
62protected:
63    virtual const char* onGetName() SK_OVERRIDE {
64        return fName.c_str();
65    }
66
67    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
68        SkPaint paint;
69        this->setupPaint(&paint);
70        paint.setStyle(SkPaint::kStroke_Style);
71        paint.setStrokeWidth(SkIntToScalar(fWidth));
72        paint.setAntiAlias(false);
73
74        SkPath path;
75        this->makePath(&path);
76
77        paint.setPathEffect(new SkDashPathEffect(fIntervals.begin(),
78                                                 fIntervals.count(), 0))->unref();
79
80        if (fDoClip) {
81            SkRect r = path.getBounds();
82            r.inset(-SkIntToScalar(20), -SkIntToScalar(20));
83            // now move it so we don't intersect
84            r.offset(0, r.height() * 3 / 2);
85            canvas->clipRect(r);
86        }
87
88        this->handlePath(canvas, path, paint, N);
89    }
90
91    virtual void handlePath(SkCanvas* canvas, const SkPath& path,
92                            const SkPaint& paint, int N) {
93        for (int i = 0; i < N; ++i) {
94//            canvas->drawPoints(SkCanvas::kLines_PointMode, 2, fPts, paint);
95            canvas->drawPath(path, paint);
96        }
97    }
98
99private:
100    typedef SkBenchmark INHERITED;
101};
102
103class RectDashBench : public DashBench {
104public:
105    RectDashBench(void* param, const SkScalar intervals[], int count, int width, bool doClip = false)
106    : INHERITED(param, intervals, count, width) {
107        fName.append("_rect");
108    }
109
110protected:
111    virtual void handlePath(SkCanvas* canvas, const SkPath& path,
112                            const SkPaint& paint, int N) SK_OVERRIDE {
113        SkPoint pts[2];
114        if (!path.isLine(pts) || pts[0].fY != pts[1].fY) {
115            this->INHERITED::handlePath(canvas, path, paint, N);
116        } else {
117            SkRect rect;
118            rect.fLeft = pts[0].fX;
119            rect.fTop = pts[0].fY - paint.getStrokeWidth() / 2;
120            rect.fRight = rect.fLeft + SkIntToScalar(fWidth);
121            rect.fBottom = rect.fTop + paint.getStrokeWidth();
122
123            SkPaint p(paint);
124            p.setStyle(SkPaint::kFill_Style);
125            p.setPathEffect(NULL);
126
127            int count = SkScalarRoundToInt((pts[1].fX - pts[0].fX) / (2*fWidth));
128            SkScalar dx = SkIntToScalar(2 * fWidth);
129
130            for (int i = 0; i < N*10; ++i) {
131                SkRect r = rect;
132                for (int j = 0; j < count; ++j) {
133                    canvas->drawRect(r, p);
134                    r.offset(dx, 0);
135                }
136            }
137        }
138    }
139
140private:
141    typedef DashBench INHERITED;
142};
143
144static void make_unit_star(SkPath* path, int n) {
145    SkScalar rad = -SK_ScalarPI / 2;
146    const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
147
148    path->moveTo(0, -SK_Scalar1);
149    for (int i = 1; i < n; i++) {
150        rad += drad;
151        SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
152        path->lineTo(cosV, sinV);
153    }
154    path->close();
155}
156
157static void make_poly(SkPath* path) {
158    make_unit_star(path, 9);
159    SkMatrix matrix;
160    matrix.setScale(SkIntToScalar(100), SkIntToScalar(100));
161    path->transform(matrix);
162}
163
164static void make_quad(SkPath* path) {
165    SkScalar x0 = SkIntToScalar(10);
166    SkScalar y0 = SkIntToScalar(10);
167    path->moveTo(x0, y0);
168    path->quadTo(x0,                    y0 + 400 * SK_Scalar1,
169                 x0 + 600 * SK_Scalar1, y0 + 400 * SK_Scalar1);
170}
171
172static void make_cubic(SkPath* path) {
173    SkScalar x0 = SkIntToScalar(10);
174    SkScalar y0 = SkIntToScalar(10);
175    path->moveTo(x0, y0);
176    path->cubicTo(x0,                    y0 + 400 * SK_Scalar1,
177                  x0 + 600 * SK_Scalar1, y0 + 400 * SK_Scalar1,
178                  x0 + 600 * SK_Scalar1, y0);
179}
180
181class MakeDashBench : public SkBenchmark {
182    SkString fName;
183    SkPath   fPath;
184    SkAutoTUnref<SkPathEffect> fPE;
185
186    enum {
187        N = SkBENCHLOOP(400)
188    };
189
190public:
191    MakeDashBench(void* param, void (*proc)(SkPath*), const char name[]) : INHERITED(param) {
192        fName.printf("makedash_%s", name);
193        proc(&fPath);
194
195        SkScalar vals[] = { SkIntToScalar(4), SkIntToScalar(4) };
196        fPE.reset(new SkDashPathEffect(vals, 2, 0));
197    }
198
199protected:
200    virtual const char* onGetName() SK_OVERRIDE {
201        return fName.c_str();
202    }
203
204    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
205        SkPath dst;
206        for (int i = 0; i < N; ++i) {
207            SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle);
208
209            fPE->filterPath(&dst, fPath, &rec);
210            dst.rewind();
211        }
212    }
213
214private:
215    typedef SkBenchmark INHERITED;
216};
217
218///////////////////////////////////////////////////////////////////////////////
219
220static const SkScalar gDots[] = { SK_Scalar1, SK_Scalar1 };
221
222#define PARAM(array)    array, SK_ARRAY_COUNT(array)
223
224static SkBenchmark* gF0(void* p) { return new DashBench(p, PARAM(gDots), 0); }
225static SkBenchmark* gF1(void* p) { return new DashBench(p, PARAM(gDots), 1); }
226static SkBenchmark* gF2(void* p) { return new DashBench(p, PARAM(gDots), 1, true); }
227static SkBenchmark* gF3(void* p) { return new DashBench(p, PARAM(gDots), 4); }
228static SkBenchmark* gF4(void* p) { return new MakeDashBench(p, make_poly, "poly"); }
229static SkBenchmark* gF5(void* p) { return new MakeDashBench(p, make_quad, "quad"); }
230static SkBenchmark* gF6(void* p) { return new MakeDashBench(p, make_cubic, "cubic"); }
231
232static BenchRegistry gR0(gF0);
233static BenchRegistry gR1(gF1);
234static BenchRegistry gR2(gF2);
235static BenchRegistry gR3(gF3);
236static BenchRegistry gR4(gF4);
237static BenchRegistry gR5(gF5);
238static BenchRegistry gR6(gF6);
239