Adds a bunch of benchmarks around creating, transforming, testing path equality,

and concatting paths. Also allows benchs to do setup / tear down steps outside
of the cons/destructor via new SkBenchmark virtuals.

Review URL: http://codereview.appspot.com/6454137/



git-svn-id: http://skia.googlecode.com/svn/trunk@5054 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2012-08-13 14:03:31 +00:00
parent d6c38137e2
commit 30e6d2c205
5 changed files with 446 additions and 1 deletions

View File

@ -13,6 +13,8 @@
#include "SkRandom.h"
#include "SkShader.h"
#include "SkString.h"
#include "SkTArray.h"
enum Flags {
kStroke_Flag = 1 << 0,
@ -218,6 +220,385 @@ private:
typedef PathBench INHERITED;
};
class RandomPathBench : public SkBenchmark {
public:
RandomPathBench(void* param) : INHERITED(param) {
}
protected:
void createData(int minVerbs,
int maxVerbs,
int pathCnt,
bool allowMoves = true,
SkRect* bounds = NULL) {
SkRect tempBounds;
if (NULL == bounds) {
tempBounds.setXYWH(0, 0, SK_Scalar1, SK_Scalar1);
bounds = &tempBounds;
}
fVerbCnts.setReserve(pathCnt);
for (int i = 0; i < pathCnt; ++i) {
int vCount = fRandom.nextRangeU(minVerbs, maxVerbs + 1);
*fVerbCnts.append() = vCount;
for (int v = 0; v < vCount; ++v) {
int verb = fRandom.nextULessThan(SkPath::kDone_Verb);
if (SkPath::kMove_Verb == verb && !allowMoves) {
--v;
continue;
}
*fVerbs.append() = static_cast<SkPath::Verb>(verb);
static const int gPointCnt[] = {
1, // kMove
1, // kLine
2, // kQuad
3, // kCubic
0, // kClose
};
int pCnt = gPointCnt[verb];
for (int p = 0; p < pCnt; ++p) {
fPoints.append()->set(fRandom.nextRangeScalar(bounds->fLeft, bounds->fRight),
fRandom.nextRangeScalar(bounds->fTop, bounds->fBottom));
}
}
}
this->restartMakingPaths();
}
void restartMakingPaths() {
fCurrPath = 0;
fCurrVerb = 0;
fCurrPoint = 0;
}
void makePath(SkPath* path) {
int vCount = fVerbCnts[fCurrPath++];
for (int v = 0; v < vCount; ++v) {
switch (fVerbs[fCurrVerb++]) {
case SkPath::kMove_Verb:
path->moveTo(fPoints[fCurrPoint]);
++fCurrPoint;
break;
case SkPath::kLine_Verb:
path->lineTo(fPoints[fCurrPoint]);
++fCurrPoint;
break;
case SkPath::kQuad_Verb:
path->quadTo(fPoints[fCurrPoint], fPoints[fCurrPoint + 1]);
fCurrPoint += 2;
break;
case SkPath::kCubic_Verb:
path->cubicTo(fPoints[fCurrPoint],
fPoints[fCurrPoint + 1],
fPoints[fCurrPoint + 2]);
fCurrPoint += 3;
break;
case SkPath::kClose_Verb:
path->close();
break;
default:
SkDEBUGFAIL("Unexpected path verb");
break;
}
}
}
void finishedMakingPaths() {
fVerbCnts.reset();
fVerbs.reset();
fPoints.reset();
}
private:
SkTDArray<int> fVerbCnts;
SkTDArray<SkPath::Verb> fVerbs;
SkTDArray<SkPoint> fPoints;
int fCurrPath;
int fCurrVerb;
int fCurrPoint;
SkRandom fRandom;
typedef SkBenchmark INHERITED;
};
class PathCreateBench : public RandomPathBench {
public:
PathCreateBench(void* param) : INHERITED(param) {
}
protected:
enum { N = SkBENCHLOOP(5000) };
virtual const char* onGetName() SK_OVERRIDE {
return "path_create";
}
virtual void onPreDraw() SK_OVERRIDE {
this->createData(10, 100, N);
SkASSERT(0 == fPaths.count());
fPaths.resize_back(N);
}
virtual void onDraw(SkCanvas*) SK_OVERRIDE {
for (int i = 0; i < N; ++i) {
this->makePath(&fPaths[i]);
}
this->restartMakingPaths();
}
virtual void onPostDraw() SK_OVERRIDE {
this->finishedMakingPaths();
fPaths.reset();
}
private:
SkTArray<SkPath> fPaths;
typedef RandomPathBench INHERITED;
};
class PathCopyBench : public RandomPathBench {
public:
PathCopyBench(void* param) : INHERITED(param) {
}
protected:
enum { N = SkBENCHLOOP(50000) };
virtual const char* onGetName() SK_OVERRIDE {
return "path_copy";
}
virtual void onPreDraw() SK_OVERRIDE {
this->createData(10, 100, N);
SkASSERT(0 == fPaths.count());
fPaths.resize_back(N);
fCopies.resize_back(N);
for (int i = 0; i < N; ++i) {
this->makePath(&fPaths[i]);
}
this->finishedMakingPaths();
}
virtual void onDraw(SkCanvas*) SK_OVERRIDE {
for (int i = 0; i < N; ++i) {
fCopies[i] = fPaths[i];
}
}
virtual void onPostDraw() SK_OVERRIDE {
fPaths.reset();
fCopies.reset();
}
private:
SkTArray<SkPath> fPaths;
SkTArray<SkPath> fCopies;
typedef RandomPathBench INHERITED;
};
class PathTransformBench : public RandomPathBench {
public:
PathTransformBench(bool inPlace, void* param)
: INHERITED(param)
, fInPlace(inPlace) {
}
protected:
enum { N = SkBENCHLOOP(30000) };
virtual const char* onGetName() SK_OVERRIDE {
return fInPlace ? "path_transform_in_place" : "path_transform_copy";
}
virtual void onPreDraw() SK_OVERRIDE {
fMatrix.setScale(5 * SK_Scalar1, 6 * SK_Scalar1);
this->createData(10, 100, N);
SkASSERT(0 == fPaths.count());
SkASSERT(0 == fTransformed.count());
fPaths.resize_back(N);
for (int i = 0; i < N; ++i) {
this->makePath(&fPaths[i]);
}
if (!fInPlace) {
fTransformed.resize_back(N);
}
}
virtual void onDraw(SkCanvas*) SK_OVERRIDE {
if (fInPlace) {
for (int i = 0; i < N; ++i) {
fPaths[i].transform(fMatrix);
}
} else {
for (int i = 0; i < N; ++i) {
fPaths[i].transform(fMatrix, &fTransformed[i]);
}
}
}
virtual void onPostDraw() SK_OVERRIDE {
fPaths.reset();
fTransformed.reset();
}
private:
SkTArray<SkPath> fPaths;
SkTArray<SkPath> fTransformed;
SkMatrix fMatrix;
bool fInPlace;
typedef RandomPathBench INHERITED;
};
class PathEqualityBench : public RandomPathBench {
public:
PathEqualityBench(void* param)
: INHERITED(param) {
}
protected:
enum { N = SkBENCHLOOP(40000) };
virtual const char* onGetName() SK_OVERRIDE {
return "path_equality_50%";
}
virtual void onPreDraw() SK_OVERRIDE {
fParity = 0;
this->createData(10, 100, N);
SkASSERT(0 == fPaths.count());
SkASSERT(0 == fCopies.count());
fPaths.resize_back(N);
fCopies.resize_back(N);
for (int i = 0; i < N; ++i) {
this->makePath(&fPaths[i]);
fCopies[i] = fPaths[i];
}
this->finishedMakingPaths();
}
virtual void onDraw(SkCanvas*) SK_OVERRIDE {
for (int i = 0; i < N; ++i) {
fParity ^= (fPaths[i] == fCopies[i & ~0x1]);
}
}
virtual void onPostDraw() SK_OVERRIDE {
fPaths.reset();
}
private:
bool fParity; // attempt to keep compiler from optimizing out the ==
SkTArray<SkPath> fPaths;
SkTArray<SkPath> fCopies;
typedef RandomPathBench INHERITED;
};
class SkBench_AddPathTest : public RandomPathBench {
public:
enum AddType {
kAdd_AddType,
kAddTrans_AddType,
kAddMatrix_AddType,
kPathTo_AddType,
kReverseAdd_AddType,
kReversePathTo_AddType,
};
SkBench_AddPathTest(AddType type, void* param)
: INHERITED(param)
, fType(type) {
fMatrix.setRotate(60 * SK_Scalar1);
}
protected:
enum { N = SkBENCHLOOP(15000) };
virtual const char* onGetName() SK_OVERRIDE {
switch (fType) {
case kAdd_AddType:
return "path_add_path";
case kAddTrans_AddType:
return "path_add_path_trans";
case kAddMatrix_AddType:
return "path_add_path_matrix";
case kPathTo_AddType:
return "path_path_to";
case kReverseAdd_AddType:
return "path_reverse_add_path";
case kReversePathTo_AddType:
return "path_reverse_path_to";
default:
SkDEBUGFAIL("Bad add type");
return "";
}
}
virtual void onPreDraw() SK_OVERRIDE {
// pathTo and reversePathTo assume a single contour path.
bool allowMoves = kPathTo_AddType != fType &&
kReversePathTo_AddType != fType;
this->createData(10, 100, 2 * N, allowMoves);
SkASSERT(0 == fPaths0.count());
SkASSERT(0 == fPaths1.count());
fPaths0.resize_back(N);
fPaths1.resize_back(N);
for (int i = 0; i < N; ++i) {
this->makePath(&fPaths0[i]);
this->makePath(&fPaths1[i]);
}
this->finishedMakingPaths();
}
virtual void onDraw(SkCanvas*) SK_OVERRIDE {
switch (fType) {
case kAdd_AddType:
for (int i = 0; i < N; ++i) {
SkPath result = fPaths0[i];
result.addPath(fPaths1[i]);
}
break;
case kAddTrans_AddType:
for (int i = 0; i < N; ++i) {
SkPath result = fPaths0[i];
result.addPath(fPaths1[i], 2 * SK_Scalar1, 5 * SK_Scalar1);
}
break;
case kAddMatrix_AddType:
for (int i = 0; i < N; ++i) {
SkPath result = fPaths0[i];
result.addPath(fPaths1[i], fMatrix);
}
break;
case kPathTo_AddType:
for (int i = 0; i < N; ++i) {
SkPath result = fPaths0[i];
result.pathTo(fPaths1[i]);
}
break;
case kReverseAdd_AddType:
for (int i = 0; i < N; ++i) {
SkPath result = fPaths0[i];
result.reverseAddPath(fPaths1[i]);
}
break;
case kReversePathTo_AddType:
for (int i = 0; i < N; ++i) {
SkPath result = fPaths0[i];
result.reversePathTo(fPaths1[i]);
}
break;
}
}
virtual void onPostDraw() SK_OVERRIDE {
fPaths0.reset();
fPaths1.reset();
}
private:
AddType fType; // or reverseAddPath
SkTArray<SkPath> fPaths0;
SkTArray<SkPath> fPaths1;
SkMatrix fMatrix;
typedef RandomPathBench INHERITED;
};
static SkBenchmark* FactT00(void* p) { return new TrianglePathBench(p, FLAGS00); }
static SkBenchmark* FactT01(void* p) { return new TrianglePathBench(p, FLAGS01); }
@ -286,3 +667,31 @@ static BenchRegistry gRegLC01(FactLC01);
static BenchRegistry gRegLL00(FactLL00);
static BenchRegistry gRegLL01(FactLL01);
static SkBenchmark* FactCreate(void* p) { return new PathCreateBench(p); }
static BenchRegistry gRegCreate(FactCreate);
static SkBenchmark* FactCopy(void* p) { return new PathCopyBench(p); }
static BenchRegistry gRegCopy(FactCopy);
static SkBenchmark* FactPathTransformInPlace(void* p) { return new PathTransformBench(true, p); }
static BenchRegistry gRegPathTransformInPlace(FactPathTransformInPlace);
static SkBenchmark* FactPathTransformCopy(void* p) { return new PathTransformBench(false, p); }
static BenchRegistry gRegPathTransformCopy(FactPathTransformCopy);
static SkBenchmark* FactEquality(void* p) { return new PathEqualityBench(p); }
static BenchRegistry gRegEquality(FactEquality);
static SkBenchmark* FactAdd(void* p) { return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType, p); }
static SkBenchmark* FactAddTrans(void* p) { return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType, p); }
static SkBenchmark* FactAddMatrix(void* p) { return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType, p); }
static SkBenchmark* FactPathTo(void* p) { return new SkBench_AddPathTest(SkBench_AddPathTest::kPathTo_AddType, p); }
static SkBenchmark* FactReverseAdd(void* p) { return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType, p); }
static SkBenchmark* FactReverseTo(void* p) { return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType, p); }
static BenchRegistry gRegAdd(FactAdd);
static BenchRegistry gRegAddTrans(FactAddTrans);
static BenchRegistry gRegAddMatrix(FactAddMatrix);
static BenchRegistry gRegPathTo(FactPathTo);
static BenchRegistry gRegReverseAdd(FactReverseAdd);
static BenchRegistry gRegReverseTo(FactReverseTo);

View File

@ -29,10 +29,18 @@ SkIPoint SkBenchmark::getSize() {
return this->onGetSize();
}
void SkBenchmark::preDraw() {
this->onPreDraw();
}
void SkBenchmark::draw(SkCanvas* canvas) {
this->onDraw(canvas);
}
void SkBenchmark::postDraw() {
this->onPostDraw();
}
void SkBenchmark::setupPaint(SkPaint* paint) {
paint->setAlpha(fForceAlpha);
paint->setAntiAlias(fForceAA);

View File

@ -39,8 +39,19 @@ public:
const char* getName();
SkIPoint getSize();
// Call before draw, allows the benchmark to do setup work outside of the
// timer. When a benchmark is repeatedly drawn, this should be called once
// before the initial draw.
void preDraw();
void draw(SkCanvas*);
// Call after draw, allows the benchmark to do cleanup work outside of the
// timer. When a benchmark is repeatedly drawn, this is only called once
// after the last draw.
void postDraw();
void setForceAlpha(int alpha) {
fForceAlpha = alpha;
}
@ -78,7 +89,9 @@ protected:
void setupPaint(SkPaint* paint);
virtual const char* onGetName() = 0;
virtual void onPreDraw() {}
virtual void onDraw(SkCanvas*) = 0;
virtual void onPostDraw() {}
virtual SkIPoint onGetSize();

View File

@ -133,6 +133,18 @@ private:
void* fParam;
};
class AutoPrePostDraw {
public:
AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) {
fBench->preDraw();
}
~AutoPrePostDraw() {
fBench->postDraw();
}
private:
SkBenchmark* fBench;
};
static void make_filename(const char name[], SkString* path) {
path->set(name);
for (int i = 0; name[i]; i++) {
@ -750,6 +762,8 @@ int main (int argc, char * const argv[]) {
logger.logProgress(str);
}
AutoPrePostDraw appd(bench);
for (int x = 0; x < configs.count(); ++x) {
int configIndex = configs[x];

View File

@ -866,6 +866,7 @@ private:
friend class SkAutoPathBoundsUpdate;
friend class SkAutoDisableOvalCheck;
friend class SkBench_AddPathTest; // perf test pathTo/reversePathTo
};
#endif