diff options
Diffstat (limited to 'chromium/third_party/skia/bench/DashBench.cpp')
-rw-r--r-- | chromium/third_party/skia/bench/DashBench.cpp | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/chromium/third_party/skia/bench/DashBench.cpp b/chromium/third_party/skia/bench/DashBench.cpp new file mode 100644 index 00000000000..f4d09c66f2e --- /dev/null +++ b/chromium/third_party/skia/bench/DashBench.cpp @@ -0,0 +1,489 @@ + +/* + * Copyright 2011 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "Benchmark.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkDashPathEffect.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkRandom.h" +#include "SkString.h" +#include "SkTDArray.h" + + +/* + * Cases to consider: + * + * 1. antialiasing on/off (esp. width <= 1) + * 2. strokewidth == 0, 1, 2 + * 3. hline, vline, diagonal, rect, oval + * 4. dots [1,1] ([N,N] where N=strokeWidth?) or arbitrary (e.g. [2,1] or [1,2,3,2]) + */ +static void path_hline(SkPath* path) { + path->moveTo(SkIntToScalar(10), SkIntToScalar(10)); + path->lineTo(SkIntToScalar(600), SkIntToScalar(10)); +} + +class DashBench : public Benchmark { +protected: + SkString fName; + SkTDArray<SkScalar> fIntervals; + int fWidth; + SkPoint fPts[2]; + bool fDoClip; + +public: + DashBench(const SkScalar intervals[], int count, int width, + bool doClip = false) { + fIntervals.append(count, intervals); + for (int i = 0; i < count; ++i) { + fIntervals[i] *= width; + } + fWidth = width; + fName.printf("dash_%d_%s", width, doClip ? "clipped" : "noclip"); + fDoClip = doClip; + + fPts[0].set(SkIntToScalar(10), SkIntToScalar(10)); + fPts[1].set(SkIntToScalar(600), SkIntToScalar(10)); + } + + virtual void makePath(SkPath* path) { + path_hline(path); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + this->setupPaint(&paint); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(SkIntToScalar(fWidth)); + paint.setAntiAlias(false); + + SkPath path; + this->makePath(&path); + + paint.setPathEffect(SkDashPathEffect::Create(fIntervals.begin(), + fIntervals.count(), 0))->unref(); + + if (fDoClip) { + SkRect r = path.getBounds(); + r.inset(-SkIntToScalar(20), -SkIntToScalar(20)); + // now move it so we don't intersect + r.offset(0, r.height() * 3 / 2); + canvas->clipRect(r); + } + + this->handlePath(canvas, path, paint, loops); + } + + virtual void handlePath(SkCanvas* canvas, const SkPath& path, + const SkPaint& paint, int N) { + for (int i = 0; i < N; ++i) { +// canvas->drawPoints(SkCanvas::kLines_PointMode, 2, fPts, paint); + canvas->drawPath(path, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class RectDashBench : public DashBench { +public: + RectDashBench(const SkScalar intervals[], int count, int width) + : INHERITED(intervals, count, width) { + fName.append("_rect"); + } + +protected: + virtual void handlePath(SkCanvas* canvas, const SkPath& path, + const SkPaint& paint, int N) SK_OVERRIDE { + SkPoint pts[2]; + if (!path.isLine(pts) || pts[0].fY != pts[1].fY) { + this->INHERITED::handlePath(canvas, path, paint, N); + } else { + SkRect rect; + rect.fLeft = pts[0].fX; + rect.fTop = pts[0].fY - paint.getStrokeWidth() / 2; + rect.fRight = rect.fLeft + SkIntToScalar(fWidth); + rect.fBottom = rect.fTop + paint.getStrokeWidth(); + + SkPaint p(paint); + p.setStyle(SkPaint::kFill_Style); + p.setPathEffect(NULL); + + int count = SkScalarRoundToInt((pts[1].fX - pts[0].fX) / (2*fWidth)); + SkScalar dx = SkIntToScalar(2 * fWidth); + + for (int i = 0; i < N*10; ++i) { + SkRect r = rect; + for (int j = 0; j < count; ++j) { + canvas->drawRect(r, p); + r.offset(dx, 0); + } + } + } + } + +private: + typedef DashBench INHERITED; +}; + +static void make_unit_star(SkPath* path, int n) { + SkScalar rad = -SK_ScalarPI / 2; + const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n; + + path->moveTo(0, -SK_Scalar1); + for (int i = 1; i < n; i++) { + rad += drad; + SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV); + path->lineTo(cosV, sinV); + } + path->close(); +} + +static void make_poly(SkPath* path) { + make_unit_star(path, 9); + SkMatrix matrix; + matrix.setScale(SkIntToScalar(100), SkIntToScalar(100)); + path->transform(matrix); +} + +static void make_quad(SkPath* path) { + SkScalar x0 = SkIntToScalar(10); + SkScalar y0 = SkIntToScalar(10); + path->moveTo(x0, y0); + path->quadTo(x0, y0 + 400 * SK_Scalar1, + x0 + 600 * SK_Scalar1, y0 + 400 * SK_Scalar1); +} + +static void make_cubic(SkPath* path) { + SkScalar x0 = SkIntToScalar(10); + SkScalar y0 = SkIntToScalar(10); + path->moveTo(x0, y0); + path->cubicTo(x0, y0 + 400 * SK_Scalar1, + x0 + 600 * SK_Scalar1, y0 + 400 * SK_Scalar1, + x0 + 600 * SK_Scalar1, y0); +} + +class MakeDashBench : public Benchmark { + SkString fName; + SkPath fPath; + SkAutoTUnref<SkPathEffect> fPE; + +public: + MakeDashBench(void (*proc)(SkPath*), const char name[]) { + fName.printf("makedash_%s", name); + proc(&fPath); + + SkScalar vals[] = { SkIntToScalar(4), SkIntToScalar(4) }; + fPE.reset(SkDashPathEffect::Create(vals, 2, 0)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { + SkPath dst; + for (int i = 0; i < loops; ++i) { + SkStrokeRec rec(SkStrokeRec::kHairline_InitStyle); + + fPE->filterPath(&dst, fPath, &rec, NULL); + dst.rewind(); + } + } + +private: + typedef Benchmark INHERITED; +}; + +/* + * We try to special case square dashes (intervals are equal to strokewidth). + */ +class DashLineBench : public Benchmark { + SkString fName; + SkScalar fStrokeWidth; + bool fIsRound; + SkAutoTUnref<SkPathEffect> fPE; + +public: + DashLineBench(SkScalar width, bool isRound) { + fName.printf("dashline_%g_%s", SkScalarToFloat(width), isRound ? "circle" : "square"); + fStrokeWidth = width; + fIsRound = isRound; + + SkScalar vals[] = { SK_Scalar1, SK_Scalar1 }; + fPE.reset(SkDashPathEffect::Create(vals, 2, 0)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint paint; + this->setupPaint(&paint); + paint.setStrokeWidth(fStrokeWidth); + paint.setStrokeCap(fIsRound ? SkPaint::kRound_Cap : SkPaint::kSquare_Cap); + paint.setPathEffect(fPE); + for (int i = 0; i < loops; ++i) { + canvas->drawLine(10 * SK_Scalar1, 10 * SK_Scalar1, + 640 * SK_Scalar1, 10 * SK_Scalar1, paint); + } + } + +private: + typedef Benchmark INHERITED; +}; + +class DrawPointsDashingBench : public Benchmark { + SkString fName; + int fStrokeWidth; + bool fDoAA; + + SkAutoTUnref<SkPathEffect> fPathEffect; + +public: + DrawPointsDashingBench(int dashLength, int strokeWidth, bool doAA) + { + fName.printf("drawpointsdash_%d_%d%s", dashLength, strokeWidth, doAA ? "_aa" : "_bw"); + fStrokeWidth = strokeWidth; + fDoAA = doAA; + + SkScalar vals[] = { SkIntToScalar(dashLength), SkIntToScalar(dashLength) }; + fPathEffect.reset(SkDashPathEffect::Create(vals, 2, SK_Scalar1)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint p; + this->setupPaint(&p); + p.setColor(SK_ColorBLACK); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(fStrokeWidth)); + p.setPathEffect(fPathEffect); + p.setAntiAlias(fDoAA); + + SkPoint pts[2] = { + { SkIntToScalar(10), 0 }, + { SkIntToScalar(640), 0 } + }; + + for (int i = 0; i < loops; ++i) { + pts[0].fY = pts[1].fY = SkIntToScalar(i % 480); + canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p); + } + } + +private: + typedef Benchmark INHERITED; +}; + +// Want to test how we handle dashing when 99% of the dash is clipped out +class GiantDashBench : public Benchmark { + SkString fName; + SkScalar fStrokeWidth; + SkPoint fPts[2]; + SkAutoTUnref<SkPathEffect> fPathEffect; + +public: + enum LineType { + kHori_LineType, + kVert_LineType, + kDiag_LineType, + kLineTypeCount + }; + + static const char* LineTypeName(LineType lt) { + static const char* gNames[] = { "hori", "vert", "diag" }; + SK_COMPILE_ASSERT(kLineTypeCount == SK_ARRAY_COUNT(gNames), names_wrong_size); + return gNames[lt]; + } + + GiantDashBench(LineType lt, SkScalar width) { + fName.printf("giantdashline_%s_%g", LineTypeName(lt), width); + fStrokeWidth = width; + + // deliberately pick intervals that won't be caught by asPoints(), so + // we can test the filterPath code-path. + const SkScalar intervals[] = { 20, 10, 10, 10 }; + fPathEffect.reset(SkDashPathEffect::Create(intervals, + SK_ARRAY_COUNT(intervals), 0)); + + SkScalar cx = 640 / 2; // center X + SkScalar cy = 480 / 2; // center Y + SkMatrix matrix; + + switch (lt) { + case kHori_LineType: + matrix.setIdentity(); + break; + case kVert_LineType: + matrix.setRotate(90, cx, cy); + break; + case kDiag_LineType: + matrix.setRotate(45, cx, cy); + break; + case kLineTypeCount: + // Not a real enum value. + break; + } + + const SkScalar overshoot = 100*1000; + const SkPoint pts[2] = { + { -overshoot, cy }, { 640 + overshoot, cy } + }; + matrix.mapPoints(fPts, pts, 2); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint p; + this->setupPaint(&p); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(fStrokeWidth); + p.setPathEffect(fPathEffect); + + for (int i = 0; i < loops; i++) { + canvas->drawPoints(SkCanvas::kLines_PointMode, 2, fPts, p); + } + } + +private: + typedef Benchmark INHERITED; +}; + +// Want to test how we draw a dashed grid (like what is used in spreadsheets) of many +// small dashed lines switching back and forth between horizontal and vertical +class DashGridBench : public Benchmark { + SkString fName; + int fStrokeWidth; + bool fDoAA; + + SkAutoTUnref<SkPathEffect> fPathEffect; + +public: + DashGridBench(int dashLength, int strokeWidth, bool doAA) { + fName.printf("dashgrid_%d_%d%s", dashLength, strokeWidth, doAA ? "_aa" : "_bw"); + fStrokeWidth = strokeWidth; + fDoAA = doAA; + + SkScalar vals[] = { SkIntToScalar(dashLength), SkIntToScalar(dashLength) }; + fPathEffect.reset(SkDashPathEffect::Create(vals, 2, SK_Scalar1)); + } + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return fName.c_str(); + } + + virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPaint p; + this->setupPaint(&p); + p.setColor(SK_ColorBLACK); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SkIntToScalar(fStrokeWidth)); + p.setPathEffect(fPathEffect); + p.setAntiAlias(fDoAA); + + SkPoint pts[4] = { + { SkIntToScalar(0), 20.5f }, + { SkIntToScalar(20), 20.5f }, + { 20.5f, SkIntToScalar(0) }, + { 20.5f, SkIntToScalar(20) } + }; + + for (int i = 0; i < loops; ++i) { + for (int j = 0; j < 10; ++j) { + for (int k = 0; k < 10; ++k) { + // Horizontal line + SkPoint horPts[2]; + horPts[0].fX = pts[0].fX + k * 22.f; + horPts[0].fY = pts[0].fY + j * 22.f; + horPts[1].fX = pts[1].fX + k * 22.f; + horPts[1].fY = pts[1].fY + j * 22.f; + canvas->drawPoints(SkCanvas::kLines_PointMode, 2, horPts, p); + + // Vertical line + SkPoint vertPts[2]; + vertPts[0].fX = pts[2].fX + k * 22.f; + vertPts[0].fY = pts[2].fY + j * 22.f; + vertPts[1].fX = pts[3].fX + k * 22.f; + vertPts[1].fY = pts[3].fY + j * 22.f; + canvas->drawPoints(SkCanvas::kLines_PointMode, 2, vertPts, p); + } + } + } + } + +private: + typedef Benchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +static const SkScalar gDots[] = { SK_Scalar1, SK_Scalar1 }; + +#define PARAM(array) array, SK_ARRAY_COUNT(array) + +DEF_BENCH( return new DashBench(PARAM(gDots), 0); ) +DEF_BENCH( return new DashBench(PARAM(gDots), 1); ) +DEF_BENCH( return new DashBench(PARAM(gDots), 1, true); ) +DEF_BENCH( return new DashBench(PARAM(gDots), 4); ) +DEF_BENCH( return new MakeDashBench(make_poly, "poly"); ) +DEF_BENCH( return new MakeDashBench(make_quad, "quad"); ) +DEF_BENCH( return new MakeDashBench(make_cubic, "cubic"); ) +DEF_BENCH( return new DashLineBench(0, false); ) +DEF_BENCH( return new DashLineBench(SK_Scalar1, false); ) +DEF_BENCH( return new DashLineBench(2 * SK_Scalar1, false); ) +DEF_BENCH( return new DashLineBench(0, true); ) +DEF_BENCH( return new DashLineBench(SK_Scalar1, true); ) +DEF_BENCH( return new DashLineBench(2 * SK_Scalar1, true); ) + +DEF_BENCH( return new DrawPointsDashingBench(1, 1, false); ) +DEF_BENCH( return new DrawPointsDashingBench(1, 1, true); ) +DEF_BENCH( return new DrawPointsDashingBench(3, 1, false); ) +DEF_BENCH( return new DrawPointsDashingBench(3, 1, true); ) +DEF_BENCH( return new DrawPointsDashingBench(5, 5, false); ) +DEF_BENCH( return new DrawPointsDashingBench(5, 5, true); ) + +/* Disable the GiantDashBench for Android devices until we can better control + * the memory usage. (https://code.google.com/p/skia/issues/detail?id=1430) + */ +#ifndef SK_BUILD_FOR_ANDROID +DEF_BENCH( return new GiantDashBench(GiantDashBench::kHori_LineType, 0); ) +DEF_BENCH( return new GiantDashBench(GiantDashBench::kVert_LineType, 0); ) +DEF_BENCH( return new GiantDashBench(GiantDashBench::kDiag_LineType, 0); ) + +// pass 2 to explicitly avoid any 1-is-the-same-as-hairline special casing + +// hori_2 is just too slow to enable at the moment +DEF_BENCH( return new GiantDashBench(GiantDashBench::kHori_LineType, 2); ) +DEF_BENCH( return new GiantDashBench(GiantDashBench::kVert_LineType, 2); ) +DEF_BENCH( return new GiantDashBench(GiantDashBench::kDiag_LineType, 2); ) + +DEF_BENCH( return new DashGridBench(1, 1, true); ) +DEF_BENCH( return new DashGridBench(1, 1, false); ) +DEF_BENCH( return new DashGridBench(3, 1, true); ) +DEF_BENCH( return new DashGridBench(3, 1, false); ) +#endif |