diff options
-rw-r--r-- | bench/PathBench.cpp | 409 | ||||
-rw-r--r-- | bench/SkBenchmark.cpp | 8 | ||||
-rw-r--r-- | bench/SkBenchmark.h | 15 | ||||
-rw-r--r-- | bench/benchmain.cpp | 14 | ||||
-rw-r--r-- | include/core/SkPath.h | 1 |
5 files changed, 446 insertions, 1 deletions
diff --git a/bench/PathBench.cpp b/bench/PathBench.cpp index d3437c41f9..f3330e42d4 100644 --- a/bench/PathBench.cpp +++ b/bench/PathBench.cpp @@ -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); diff --git a/bench/SkBenchmark.cpp b/bench/SkBenchmark.cpp index 19bbf599e4..c8552d59d6 100644 --- a/bench/SkBenchmark.cpp +++ b/bench/SkBenchmark.cpp @@ -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); diff --git a/bench/SkBenchmark.h b/bench/SkBenchmark.h index 1d6fb41866..28314ea11b 100644 --- a/bench/SkBenchmark.h +++ b/bench/SkBenchmark.h @@ -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(); diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp index 7cfa849ec7..0ea48e9ed4 100644 --- a/bench/benchmain.cpp +++ b/bench/benchmain.cpp @@ -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]; diff --git a/include/core/SkPath.h b/include/core/SkPath.h index a6d78ec9fe..2bd2d76777 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -866,6 +866,7 @@ private: friend class SkAutoPathBoundsUpdate; friend class SkAutoDisableOvalCheck; + friend class SkBench_AddPathTest; // perf test pathTo/reversePathTo }; #endif |