diff options
-rw-r--r-- | bench/GeometryBench.cpp | 103 | ||||
-rw-r--r-- | src/core/SkGeometry.cpp | 42 | ||||
-rw-r--r-- | src/core/SkGeometry.h | 5 | ||||
-rw-r--r-- | tests/GeometryTest.cpp | 32 |
4 files changed, 156 insertions, 26 deletions
diff --git a/bench/GeometryBench.cpp b/bench/GeometryBench.cpp index 1d8575735f..24d5c34620 100644 --- a/bench/GeometryBench.cpp +++ b/bench/GeometryBench.cpp @@ -132,46 +132,115 @@ DEF_BENCH( return new GeoRectBench_sort; ) /////////////////////////////////////////////////////////////////////////////////////////////////// -class EvalQuadAt0 : public GeometryBench { +class QuadBenchBase : public GeometryBench { +protected: SkPoint fPts[3]; public: - EvalQuadAt0() : GeometryBench("evalquadat0") { + QuadBenchBase(const char name[]) : GeometryBench(name) { SkRandom rand; for (int i = 0; i < 3; ++i) { fPts[i].set(rand.nextUScalar1(), rand.nextUScalar1()); } } - +}; + +class EvalQuadAt0 : public QuadBenchBase { +public: + EvalQuadAt0() : QuadBenchBase("evalquadat0") {} protected: void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { SkPoint result; for (int outer = 0; outer < loops; ++outer) { - for (int i = 0; i < 10000; ++i) { - SkEvalQuadAt(fPts, 0.5f, &result); - } + SkEvalQuadAt(fPts, 0.5f, &result); + SkEvalQuadAt(fPts, 0.5f, &result); + SkEvalQuadAt(fPts, 0.5f, &result); + SkEvalQuadAt(fPts, 0.5f, &result); } } }; DEF_BENCH( return new EvalQuadAt0; ) -class EvalQuadAt1 : public GeometryBench { - SkPoint fPts[3]; +class EvalQuadAt1 : public QuadBenchBase { public: - EvalQuadAt1() : GeometryBench("evalquadat1") { - SkRandom rand; - for (int i = 0; i < 3; ++i) { - fPts[i].set(rand.nextUScalar1(), rand.nextUScalar1()); + EvalQuadAt1() : QuadBenchBase("evalquadat1") {} +protected: + void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPoint result; + for (int outer = 0; outer < loops; ++outer) { + result = SkEvalQuadAt(fPts, 0.5f); + result = SkEvalQuadAt(fPts, 0.5f); + result = SkEvalQuadAt(fPts, 0.5f); + result = SkEvalQuadAt(fPts, 0.5f); } } - +}; +DEF_BENCH( return new EvalQuadAt1; ) + +//////// + +class EvalQuadTangentAt0 : public QuadBenchBase { +public: + EvalQuadTangentAt0() : QuadBenchBase("evalquadtangentat0") {} protected: void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPoint result; for (int outer = 0; outer < loops; ++outer) { - for (int i = 0; i < 10000; ++i) { - SkEvalQuadAt(fPts, 0.5f); - } + SkEvalQuadAt(fPts, 0.5f, NULL, &result); + SkEvalQuadAt(fPts, 0.5f, NULL, &result); + SkEvalQuadAt(fPts, 0.5f, NULL, &result); + SkEvalQuadAt(fPts, 0.5f, NULL, &result); } } }; -DEF_BENCH( return new EvalQuadAt1; ) +DEF_BENCH( return new EvalQuadTangentAt0; ) + +class EvalQuadTangentAt1 : public QuadBenchBase { +public: + EvalQuadTangentAt1() : QuadBenchBase("evalquadtangentat1") {} +protected: + void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPoint result; + for (int outer = 0; outer < loops; ++outer) { + result = SkEvalQuadTangentAt(fPts, 0.5f); + result = SkEvalQuadTangentAt(fPts, 0.5f); + result = SkEvalQuadTangentAt(fPts, 0.5f); + result = SkEvalQuadTangentAt(fPts, 0.5f); + } + } +}; +DEF_BENCH( return new EvalQuadTangentAt1; ) + +//////// + +class ChopQuadAt0 : public QuadBenchBase { +public: + ChopQuadAt0() : QuadBenchBase("chopquadat0") {} +protected: + void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPoint dst[5]; + for (int outer = 0; outer < loops; ++outer) { + SkChopQuadAt(fPts, dst, 0.5f); + SkChopQuadAt(fPts, dst, 0.5f); + SkChopQuadAt(fPts, dst, 0.5f); + SkChopQuadAt(fPts, dst, 0.5f); + } + } +}; +DEF_BENCH( return new ChopQuadAt0; ) + +class ChopQuadAt1 : public QuadBenchBase { +public: + ChopQuadAt1() : QuadBenchBase("chopquadat1") {} +protected: + void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE { + SkPoint dst[5]; + for (int outer = 0; outer < loops; ++outer) { + SkChopQuadAt2(fPts, dst, 0.5f); + SkChopQuadAt2(fPts, dst, 0.5f); + SkChopQuadAt2(fPts, dst, 0.5f); + SkChopQuadAt2(fPts, dst, 0.5f); + } + } +}; +DEF_BENCH( return new ChopQuadAt1; ) diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp index 6d14e4bb54..aea1fe5665 100644 --- a/src/core/SkGeometry.cpp +++ b/src/core/SkGeometry.cpp @@ -7,6 +7,7 @@ #include "SkGeometry.h" #include "SkMatrix.h" +#include "Sk2x.h" /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul. @@ -127,8 +128,6 @@ void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tange } } -#include "Sk2x.h" - SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) { SkASSERT(src); SkASSERT(t >= 0 && t <= SK_Scalar1); @@ -147,6 +146,23 @@ SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) { return result; } +SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) { + SkASSERT(src); + SkASSERT(t >= 0 && t <= SK_Scalar1); + + Sk2f P0 = Sk2f::Load(&src[0].fX); + Sk2f P1 = Sk2f::Load(&src[1].fX); + Sk2f P2 = Sk2f::Load(&src[2].fX); + + Sk2f B = P1 - P0; + Sk2f A = P2 - P1 - B; + Sk2f T = A * Sk2f(t) + B; + + SkVector result; + (T + T).store(&result.fX); + return result; +} + static void interp_quad_coords(const SkScalar* src, SkScalar* dst, SkScalar t) { SkScalar ab = SkScalarInterp(src[0], src[2], t); SkScalar bc = SkScalarInterp(src[2], src[4], t); @@ -165,6 +181,28 @@ void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t) { interp_quad_coords(&src[0].fY, &dst[0].fY, t); } +static inline Sk2s interp(const Sk2s& v0, const Sk2s& v1, const Sk2s& t) { + return v0 + (v1 - v0) * t; +} + +void SkChopQuadAt2(const SkPoint src[3], SkPoint dst[5], SkScalar t) { + SkASSERT(t > 0 && t < SK_Scalar1); + + Sk2s p0 = Sk2f::Load(&src[0].fX); + Sk2s p1 = Sk2f::Load(&src[1].fX); + Sk2s p2 = Sk2f::Load(&src[2].fX); + Sk2s tt = Sk2s(t); + + Sk2s p01 = interp(p0, p1, tt); + Sk2s p12 = interp(p1, p2, tt); + + p0.store(&dst[0].fX); + p01.store(&dst[1].fX); + interp(p01, p12, tt).store(&dst[2].fX); + p12.store(&dst[3].fX); + p2.store(&dst[4].fX); +} + void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5]) { SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX); SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY); diff --git a/src/core/SkGeometry.h b/src/core/SkGeometry.h index ff863a2294..5f7aa5e7b3 100644 --- a/src/core/SkGeometry.h +++ b/src/core/SkGeometry.h @@ -17,11 +17,14 @@ int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]); /////////////////////////////////////////////////////////////////////////////// +SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t); +SkPoint SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t); +void SkChopQuadAt2(const SkPoint src[3], SkPoint dst[5], SkScalar t); + /** Set pt to the point on the src quadratic specified by t. t must be 0 <= t <= 1.0 */ void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent = NULL); -SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t); /** Given a src quadratic bezier, chop it at the specified t value, where 0 < t < 1, and return the two new quadratics in dst: diff --git a/tests/GeometryTest.cpp b/tests/GeometryTest.cpp index 9be6000a0e..aba8dd224b 100644 --- a/tests/GeometryTest.cpp +++ b/tests/GeometryTest.cpp @@ -34,6 +34,16 @@ static void testChopCubic(skiatest::Reporter* reporter) { } } +static void check_pairs(skiatest::Reporter* reporter, int index, SkScalar t, const char name[], + SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1) { + bool eq = SkScalarNearlyEqual(x0, x1) && SkScalarNearlyEqual(y0, y1); + if (!eq) { + SkDebugf("%s [%d %g] p0 [%10.8f %10.8f] p1 [%10.8f %10.8f]\n", + name, index, t, x0, y0, x1, y1); + REPORTER_ASSERT(reporter, eq); + } +} + static void test_evalquadat(skiatest::Reporter* reporter) { SkRandom rand; for (int i = 0; i < 1000; ++i) { @@ -41,17 +51,27 @@ static void test_evalquadat(skiatest::Reporter* reporter) { for (int j = 0; j < 3; ++j) { pts[j].set(rand.nextSScalar1() * 100, rand.nextSScalar1() * 100); } - SkScalar t = 0; const SkScalar dt = SK_Scalar1 / 128; - for (int j = 0; j < 128; ++j) { + SkScalar t = dt; + for (int j = 1; j < 128; ++j) { SkPoint r0; SkEvalQuadAt(pts, t, &r0); SkPoint r1 = SkEvalQuadAt(pts, t); - bool eq = SkScalarNearlyEqual(r0.fX, r1.fX) && SkScalarNearlyEqual(r0.fY, r1.fY); - if (!eq) { - SkDebugf("[%d %g] p0 [%10.8f %10.8f] p1 [%10.8f %10.8f]\n", i, t, r0.fX, r0.fY, r1.fX, r1.fY); - REPORTER_ASSERT(reporter, eq); + check_pairs(reporter, i, t, "quad-pos", r0.fX, r0.fY, r1.fX, r1.fY); + + SkVector v0; + SkEvalQuadAt(pts, t, NULL, &v0); + SkVector v1 = SkEvalQuadTangentAt(pts, t); + check_pairs(reporter, i, t, "quad-tan", v0.fX, v0.fY, v1.fX, v1.fY); + + SkPoint dst0[5], dst1[5]; + SkChopQuadAt(pts, dst0, t); + SkChopQuadAt2(pts, dst1, t); + for (int k = 0; k < 5; ++k) { + check_pairs(reporter, i, t, "chop-quad", + dst0[k].fX, dst0[k].fY, dst1[k].fX, dst1[k].fY); } + t += dt; } } |