blob: f15c5719cfe27ef349ed5352d545483e98a51b84 [file] [log] [blame]
/*
* 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 "SkCommandLineFlags.h"
#include "SkGradientShader.h"
#include "SkPaint.h"
#include "SkRandom.h"
#include "SkShader.h"
#include "SkString.h"
DEFINE_double(strokeWidth, -1.0, "If set, use this stroke width in RectBench.");
class RectBench : public Benchmark {
public:
int fShift, fStroke;
enum {
W = 640,
H = 480,
N = 300,
};
SkRect fRects[N];
SkColor fColors[N];
bool fAA;
bool fPerspective;
RectBench(int shift, int stroke = 0, bool aa = true, bool perspective = false)
: fShift(shift)
, fStroke(stroke)
, fAA(aa)
, fPerspective(perspective) {}
const char* computeName(const char root[]) {
fBaseName.printf("%s_%d", root, fShift);
if (fStroke > 0) {
fBaseName.appendf("_stroke_%d", fStroke);
}
if (fAA) {
fBaseName.appendf("_aa");
} else {
fBaseName.appendf("_bw");
}
if (fPerspective) {
fBaseName.appendf("_persp");
}
return fBaseName.c_str();
}
protected:
virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) {
c->drawRect(r, p);
}
const char* onGetName() override { return computeName("rects"); }
void onDelayedSetup() override {
SkRandom rand;
const SkScalar offset = SK_Scalar1/3;
for (int i = 0; i < N; i++) {
int x = rand.nextU() % W;
int y = rand.nextU() % H;
int w = rand.nextU() % W;
int h = rand.nextU() % H;
w >>= fShift;
h >>= fShift;
x -= w/2;
y -= h/2;
fRects[i].set(SkIntToScalar(x), SkIntToScalar(y),
SkIntToScalar(x+w), SkIntToScalar(y+h));
fRects[i].offset(offset, offset);
fColors[i] = rand.nextU() | 0xFF808080;
}
}
void onDraw(int loops, SkCanvas* canvas) override {
SkPaint paint;
if (fStroke > 0) {
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(SkIntToScalar(fStroke));
}
if (fPerspective) {
// Apply some fixed perspective to change how ops may draw the rects
SkMatrix perspective;
perspective.setIdentity();
perspective.setPerspX(1e-4f);
perspective.setPerspY(1e-3f);
perspective.setSkewX(0.1f);
canvas->concat(perspective);
}
for (int i = 0; i < loops; i++) {
paint.setColor(fColors[i % N]);
this->setupPaint(&paint);
this->drawThisRect(canvas, fRects[i % N], paint);
}
}
void setupPaint(SkPaint* paint) override {
this->INHERITED::setupPaint(paint);
paint->setAntiAlias(fAA);
}
private:
SkString fBaseName;
typedef Benchmark INHERITED;
};
class SrcModeRectBench : public RectBench {
public:
SrcModeRectBench() : INHERITED(1, 0) {
fMode = SkBlendMode::kSrc;
}
protected:
void setupPaint(SkPaint* paint) override {
this->INHERITED::setupPaint(paint);
// srcmode is most interesting when we're not opaque
paint->setAlpha(0x80);
paint->setBlendMode(fMode);
}
const char* onGetName() override {
fName.set(this->INHERITED::onGetName());
fName.prepend("srcmode_");
return fName.c_str();
}
private:
SkBlendMode fMode;
SkString fName;
typedef RectBench INHERITED;
};
class TransparentRectBench : public RectBench {
public:
TransparentRectBench() : INHERITED(1, 0) {}
protected:
void setupPaint(SkPaint* paint) override {
this->INHERITED::setupPaint(paint);
// draw non opaque rect
paint->setAlpha(0x80);
}
const char* onGetName() override {
fName.set(this->INHERITED::onGetName());
fName.prepend("transparent_");
return fName.c_str();
}
private:
SkString fName;
typedef RectBench INHERITED;
};
// Adds a shader to the paint that requires local coordinates to be used
class LocalCoordsRectBench : public RectBench {
public:
LocalCoordsRectBench(bool aa, bool perspective = false) : INHERITED(1, 0, aa, perspective) { }
protected:
void onDelayedSetup() override {
this->INHERITED::onDelayedSetup();
// Create the shader once, so that isn't included in the timing
SkPoint pts[2] = { {0.f, 0.f}, {50.f, 50.f} };
SkColor colors[] = { SK_ColorWHITE, SK_ColorBLUE };
fShader = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
}
void setupPaint(SkPaint* paint) override {
this->INHERITED::setupPaint(paint);
paint->setShader(fShader);
}
const char* onGetName() override {
fName.set(this->INHERITED::onGetName());
fName.append("_localcoords");
return fName.c_str();
}
private:
SkString fName;
sk_sp<SkShader> fShader;
typedef RectBench INHERITED;
};
class OvalBench : public RectBench {
public:
OvalBench(int shift, int stroke = 0) : RectBench(shift, stroke) {}
protected:
void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) override {
c->drawOval(r, p);
}
const char* onGetName() override { return computeName("ovals"); }
};
class RRectBench : public RectBench {
public:
RRectBench(int shift, int stroke = 0) : RectBench(shift, stroke) {}
protected:
void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) override {
c->drawRoundRect(r, r.width() / 4, r.height() / 4, p);
}
const char* onGetName() override { return computeName("rrects"); }
};
class PointsBench : public RectBench {
public:
SkCanvas::PointMode fMode;
PointsBench(SkCanvas::PointMode mode, const char* name)
: RectBench(2)
, fMode(mode) {
fName = name;
}
protected:
void onDraw(int loops, SkCanvas* canvas) override {
SkScalar gSizes[] = {
SkIntToScalar(7), 0
};
size_t sizes = SK_ARRAY_COUNT(gSizes);
if (FLAGS_strokeWidth >= 0) {
gSizes[0] = (SkScalar)FLAGS_strokeWidth;
sizes = 1;
}
SkPaint paint;
paint.setStrokeCap(SkPaint::kRound_Cap);
for (int loop = 0; loop < loops; loop++) {
for (size_t i = 0; i < sizes; i++) {
paint.setStrokeWidth(gSizes[i]);
this->setupPaint(&paint);
canvas->drawPoints(fMode, N * 2, reinterpret_cast<SkPoint*>(fRects), paint);
paint.setColor(fColors[i % N]);
}
}
}
const char* onGetName() override { return fName.c_str(); }
private:
SkString fName;
};
/*******************************************************************************
* to bench BlitMask [Opaque, Black, color, shader]
*******************************************************************************/
class BlitMaskBench : public RectBench {
public:
enum kMaskType {
kMaskOpaque = 0,
kMaskBlack,
kMaskColor,
KMaskShader
};
SkCanvas::PointMode fMode;
BlitMaskBench(SkCanvas::PointMode mode,
BlitMaskBench::kMaskType type, const char* name) :
RectBench(2), fMode(mode), _type(type) {
fName = name;
}
protected:
void onDraw(int loops, SkCanvas* canvas) override {
SkScalar gSizes[] = {
SkIntToScalar(13), SkIntToScalar(24)
};
size_t sizes = SK_ARRAY_COUNT(gSizes);
if (FLAGS_strokeWidth >= 0) {
gSizes[0] = (SkScalar)FLAGS_strokeWidth;
sizes = 1;
}
SkRandom rand;
SkColor color = 0xFF000000;
U8CPU alpha = 0xFF;
SkPaint paint;
paint.setStrokeCap(SkPaint::kRound_Cap);
if (_type == KMaskShader) {
SkBitmap srcBM;
srcBM.allocN32Pixels(10, 1);
srcBM.eraseColor(0xFF00FF00);
paint.setShader(SkShader::MakeBitmapShader(srcBM, SkShader::kClamp_TileMode,
SkShader::kClamp_TileMode));
}
for (int loop = 0; loop < loops; loop++) {
for (size_t i = 0; i < sizes; i++) {
switch (_type) {
case kMaskOpaque:
color = fColors[i];
alpha = 0xFF;
break;
case kMaskBlack:
alpha = 0xFF;
color = 0xFF000000;
break;
case kMaskColor:
color = fColors[i];
alpha = rand.nextU() & 255;
break;
case KMaskShader:
break;
}
paint.setStrokeWidth(gSizes[i]);
this->setupPaint(&paint);
paint.setColor(color);
paint.setAlpha(alpha);
canvas->drawPoints(fMode, N * 2, reinterpret_cast<SkPoint*>(fRects), paint);
}
}
}
const char* onGetName() override { return fName.c_str(); }
private:
typedef RectBench INHERITED;
kMaskType _type;
SkString fName;
};
// AA rects
DEF_BENCH(return new RectBench(1, 0, true);)
DEF_BENCH(return new RectBench(1, 4, true);)
DEF_BENCH(return new RectBench(3, 0, true);)
DEF_BENCH(return new RectBench(3, 4, true);)
// Non-AA rects
DEF_BENCH(return new RectBench(1, 0, false);)
DEF_BENCH(return new RectBench(1, 4, false);)
DEF_BENCH(return new RectBench(3, 0, false);)
DEF_BENCH(return new RectBench(3, 4, false);)
DEF_BENCH(return new OvalBench(1);)
DEF_BENCH(return new OvalBench(3);)
DEF_BENCH(return new OvalBench(1, 4);)
DEF_BENCH(return new OvalBench(3, 4);)
DEF_BENCH(return new RRectBench(1);)
DEF_BENCH(return new RRectBench(1, 4);)
DEF_BENCH(return new RRectBench(3);)
DEF_BENCH(return new RRectBench(3, 4);)
DEF_BENCH(return new PointsBench(SkCanvas::kPoints_PointMode, "points");)
DEF_BENCH(return new PointsBench(SkCanvas::kLines_PointMode, "lines");)
DEF_BENCH(return new PointsBench(SkCanvas::kPolygon_PointMode, "polygon");)
DEF_BENCH(return new SrcModeRectBench();)
DEF_BENCH(return new TransparentRectBench();)
DEF_BENCH(return new LocalCoordsRectBench(true);)
DEF_BENCH(return new LocalCoordsRectBench(false);)
// Perspective rects
DEF_BENCH(return new RectBench(1, 0, true, true);)
DEF_BENCH(return new RectBench(1, 0, false, true);)
DEF_BENCH(return new LocalCoordsRectBench(true, true);)
DEF_BENCH(return new LocalCoordsRectBench(false, true);)
/* init the blitmask bench
*/
DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode,
BlitMaskBench::kMaskOpaque,
"maskopaque");)
DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode,
BlitMaskBench::kMaskBlack,
"maskblack");)
DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode,
BlitMaskBench::kMaskColor,
"maskcolor");)
DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode,
BlitMaskBench::KMaskShader,
"maskshader");)