diff options
-rw-r--r-- | bench/PathBench.cpp | 107 | ||||
-rw-r--r-- | include/core/SkGeometry.h | 9 | ||||
-rw-r--r-- | src/core/SkGeometry.cpp | 53 |
3 files changed, 127 insertions, 42 deletions
diff --git a/bench/PathBench.cpp b/bench/PathBench.cpp index dc95ea669b..6ef78ccdd7 100644 --- a/bench/PathBench.cpp +++ b/bench/PathBench.cpp @@ -15,7 +15,6 @@ #include "SkString.h" #include "SkTArray.h" - enum Flags { kStroke_Flag = 1 << 0, kBig_Flag = 1 << 1 @@ -908,22 +907,120 @@ public: fRQ.fPts[2].set(100, 100); fRQ.fW = SkScalarCos(SK_ScalarPI/4); } - + private: virtual const char* onGetName() SK_OVERRIDE { return "ratquad-chop-half"; } - + virtual void onDraw(SkCanvas*) SK_OVERRIDE { SkConic dst[2]; for (int i = 0; i < N; ++i) { fRQ.chop(dst); } } + + typedef SkBenchmark INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// +static void rand_conic(SkConic* conic, SkRandom& rand) { + for (int i = 0; i < 3; ++i) { + conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100); + } + if (rand.nextUScalar1() > 0.5f) { + conic->fW = rand.nextUScalar1(); + } else { + conic->fW = 1 + rand.nextUScalar1() * 4; + } +} + +class ConicBench : public SkBenchmark { +public: + ConicBench(void* param) : INHERITED(param) { + SkRandom rand; + for (int i = 0; i < CONICS; ++i) { + rand_conic(&fConics[i], rand); + } + fIsRendering = false; + } + +protected: + enum { + N = 20000, + CONICS = 100 + }; + SkConic fConics[CONICS]; + +private: typedef SkBenchmark INHERITED; }; +class ConicBench_ComputeError : public ConicBench { +public: + ConicBench_ComputeError(void* param) : INHERITED(param) {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "conic-compute-error"; + } + + virtual void onDraw(SkCanvas*) SK_OVERRIDE { + SkVector err; + for (int i = 0; i < N; ++i) { + for (int j = 0; j < CONICS; ++j) { + fConics[j].computeAsQuadError(&err); + } + } + } + +private: + typedef ConicBench INHERITED; +}; + +class ConicBench_asQuadTol : public ConicBench { +public: + ConicBench_asQuadTol(void* param) : INHERITED(param) {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "conic-asQuadTol"; + } + + virtual void onDraw(SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < N; ++i) { + for (int j = 0; j < CONICS; ++j) { + fConics[j].asQuadTol(SK_ScalarHalf); + } + } + } + +private: + typedef ConicBench INHERITED; +}; + +class ConicBench_quadPow2 : public ConicBench { +public: + ConicBench_quadPow2(void* param) : INHERITED(param) {} + +protected: + virtual const char* onGetName() SK_OVERRIDE { + return "conic-quadPow2"; + } + + virtual void onDraw(SkCanvas*) SK_OVERRIDE { + for (int i = 0; i < N; ++i) { + for (int j = 0; j < CONICS; ++j) { + fConics[j].computeQuadPOW2(SK_ScalarHalf); + } + } + } + +private: + typedef ConicBench INHERITED; +}; + /////////////////////////////////////////////////////////////////////////////// const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100)); @@ -983,3 +1080,7 @@ DEF_BENCH( return new ConservativelyContainsBench(p, ConservativelyContainsBench DEF_BENCH( return new ConicBench_Chop5(p) ) DEF_BENCH( return new ConicBench_ChopHalf(p) ) +DEF_BENCH( return new ConicBench_ComputeError(p) ) +DEF_BENCH( return new ConicBench_asQuadTol(p) ) +DEF_BENCH( return new ConicBench_quadPow2(p) ) + diff --git a/include/core/SkGeometry.h b/include/core/SkGeometry.h index 97997c410a..1251fcf98d 100644 --- a/include/core/SkGeometry.h +++ b/include/core/SkGeometry.h @@ -220,13 +220,8 @@ struct SkConic { void chopAt(SkScalar t, SkConic dst[2]) const; void chop(SkConic dst[2]) const; - /** - * Return the max difference between the conic and its framing quadratic - * in err and return true. If the conic is degenerate (a line between - * pts[0] and pts[2]) or has a negative weight, return false and ignore - * the diff parameter. - */ - bool computeErrorAsQuad(SkVector* err) const; + void computeAsQuadError(SkVector* err) const; + bool asQuadTol(SkScalar tol) const; int computeQuadPOW2(SkScalar tol) const; int chopIntoQuadsPOW2(SkPoint pts[], int pow2) const; diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp index dcdbf9c2a4..b6b23bcfd0 100644 --- a/src/core/SkGeometry.cpp +++ b/src/core/SkGeometry.cpp @@ -1547,32 +1547,36 @@ void SkConic::chop(SkConic dst[2]) const { * "High order approximation of conic sections by quadratic splines" * by Michael Floater, 1993 */ -bool SkConic::computeErrorAsQuad(SkVector* err) const { - if (fW <= 0) { - return false; - } - SkScalar a = fW - 1; - SkScalar k = a / (4 * (2 + a)); - err->set(k * (fPts[0].fX - 2 * fPts[1].fX + fPts[2].fX), - k * (fPts[0].fY - 2 * fPts[1].fY + fPts[2].fY)); - return true; +#define AS_QUAD_ERROR_SETUP \ + SkScalar a = fW - 1; \ + SkScalar k = a / (4 * (2 + a)); \ + SkScalar x = k * (fPts[0].fX - 2 * fPts[1].fX + fPts[2].fX); \ + SkScalar y = k * (fPts[0].fY - 2 * fPts[1].fY + fPts[2].fY); + +void SkConic::computeAsQuadError(SkVector* err) const { + AS_QUAD_ERROR_SETUP + err->set(x, y); +} + +bool SkConic::asQuadTol(SkScalar tol) const { + AS_QUAD_ERROR_SETUP + return (x * x + y * y) <= tol * tol; } int SkConic::computeQuadPOW2(SkScalar tol) const { - SkVector diff; - if (!this->computeErrorAsQuad(&diff)) { + AS_QUAD_ERROR_SETUP + SkScalar error = SkScalarSqrt(x * x + y * y) - tol; + + if (error <= 0) { return 0; } - - // the error reduces by 4 with each subdivision, so return the subdivision - // count needed. - SkScalar error = diff.length() - SkScalarAbs(tol); uint32_t ierr = (uint32_t)error; - return (33 - SkCLZ(ierr)) >> 1; + return (34 - SkCLZ(ierr)) >> 1; } static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) { SkASSERT(level >= 0); + if (0 == level) { memcpy(pts, &src.fPts[1], 2 * sizeof(SkPoint)); return pts + 2; @@ -1586,22 +1590,7 @@ static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) { } int SkConic::chopIntoQuadsPOW2(SkPoint pts[], int pow2) const { - if (pow2 < 0) { - return 0; - } - if (0 == pow2) { - memcpy(pts, fPts, 3 * sizeof(SkPoint)); - return 1; - } - if (1 == pow2) { - SkConic dst[2]; - this->chop(dst); - memcpy(pts, dst[0].fPts, 3 * sizeof(SkPoint)); - pts += 3; - memcpy(pts, dst[1].fPts + 1, 2 * sizeof(SkPoint)); - return 2; - } - + SkASSERT(pow2 >= 0); *pts = fPts[0]; SkDEBUGCODE(SkPoint* endPts =) subdivide(*this, pts + 1, pow2); SkASSERT(endPts - pts == (2 * (1 << pow2) + 1)); |