From 79cf7ca5af9b03f21f97eb9d174491390c9d6c1d Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 9 Jul 2024 14:00:26 +0900 Subject: [PATCH] common/math: introduced custom atan2() the custom atan2 algorithm by Remez. see: https://en.wikipedia.org/wiki/Remez_algorithm This improved the Lottie example by ~2ms. Total atan2 performance time was reduced by 43% --- src/common/tvgLines.cpp | 2 +- src/common/tvgMath.cpp | 14 ++++++++++++++ src/common/tvgMath.h | 3 ++- src/loaders/lottie/tvgLottieBuilder.cpp | 8 ++++---- src/loaders/lottie/tvgLottieModel.cpp | 3 ++- src/loaders/lottie/tvgLottieProperty.h | 2 +- src/loaders/svg/tvgSvgPath.cpp | 4 ++-- src/renderer/gl_engine/tvgGlTessellator.cpp | 3 ++- src/renderer/sw_engine/tvgSwMath.cpp | 2 +- 9 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/common/tvgLines.cpp b/src/common/tvgLines.cpp index 98b8423c..48914dd5 100644 --- a/src/common/tvgLines.cpp +++ b/src/common/tvgLines.cpp @@ -238,7 +238,7 @@ float bezAngleAt(const Bezier& bz, float t) pt.x *= 3; pt.y *= 3; - return mathRad2Deg(atan2(pt.y, pt.x)); + return mathRad2Deg(mathAtan2(pt.y, pt.x)); } diff --git a/src/common/tvgMath.cpp b/src/common/tvgMath.cpp index 3ea69389..5d583721 100644 --- a/src/common/tvgMath.cpp +++ b/src/common/tvgMath.cpp @@ -22,6 +22,20 @@ #include "tvgMath.h" +//see: https://en.wikipedia.org/wiki/Remez_algorithm +float mathAtan2(float y, float x) +{ + if (y == 0.0f) return 0.0f; + + auto a = std::min(fabsf(x), fabsf(y)) / std::max(fabsf(x), fabsf(y)); + auto s = a * a; + auto r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a; + if (fabsf(y) > fabsf(x)) r = 1.57079637f - r; + if (x < 0) r = 3.14159274f - r; + if (y < 0) return -r; + return r; +} + bool mathInverse(const Matrix* m, Matrix* out) { diff --git a/src/common/tvgMath.h b/src/common/tvgMath.h index d84400de..cf66183b 100644 --- a/src/common/tvgMath.h +++ b/src/common/tvgMath.h @@ -39,6 +39,7 @@ /* General functions */ /************************************************************************/ +float mathAtan2(float y, float x); static inline float mathDeg2Rad(float degree) { @@ -76,7 +77,7 @@ bool operator==(const Matrix& lhs, const Matrix& rhs); static inline bool mathRightAngle(const Matrix* m) { - auto radian = fabsf(atan2f(m->e21, m->e11)); + auto radian = fabsf(mathAtan2(m->e21, m->e11)); if (radian < FLOAT_EPSILON || mathEqual(radian, MATH_PI2) || mathEqual(radian, MATH_PI)) return true; return false; } diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index 321e0ca3..1028034a 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -724,10 +724,10 @@ static void _updateStar(LottieGroup* parent, LottiePolyStar* star, Matrix* trans y = radius * sinf(angle); if (hasRoundness) { - auto cp1Theta = (atan2f(previousY, previousX) - MATH_PI2 * direction); + auto cp1Theta = (mathAtan2(previousY, previousX) - MATH_PI2 * direction); auto cp1Dx = cosf(cp1Theta); auto cp1Dy = sinf(cp1Theta); - auto cp2Theta = (atan2f(y, x) - MATH_PI2 * direction); + auto cp2Theta = (mathAtan2(y, x) - MATH_PI2 * direction); auto cp2Dx = cosf(cp2Theta); auto cp2Dy = sinf(cp2Theta); @@ -810,10 +810,10 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr y = (radius * sinf(angle)); if (hasRoundness) { - auto cp1Theta = atan2f(previousY, previousX) - MATH_PI2 * direction; + auto cp1Theta = mathAtan2(previousY, previousX) - MATH_PI2 * direction; auto cp1Dx = cosf(cp1Theta); auto cp1Dy = sinf(cp1Theta); - auto cp2Theta = atan2f(y, x) - MATH_PI2 * direction; + auto cp2Theta = mathAtan2(y, x) - MATH_PI2 * direction; auto cp2Dx = cosf(cp2Theta); auto cp2Dy = sinf(cp2Theta); diff --git a/src/loaders/lottie/tvgLottieModel.cpp b/src/loaders/lottie/tvgLottieModel.cpp index e66f52d6..80f312e8 100644 --- a/src/loaders/lottie/tvgLottieModel.cpp +++ b/src/loaders/lottie/tvgLottieModel.cpp @@ -20,6 +20,7 @@ * SOFTWARE. */ +#include "tvgMath.h" #include "tvgPaint.h" #include "tvgFill.h" #include "tvgLottieModel.h" @@ -249,7 +250,7 @@ Fill* LottieGradient::fill(float frameNo, LottieExpressions* exps) P(static_cast(fill))->radial(s.x, s.y, r, s.x, s.y, 0.0f); } else { if (mathEqual(progress, 1.0f)) progress = 0.99f; - auto startAngle = mathRad2Deg(atan2(e.y - s.y, e.x - s.x)); + auto startAngle = mathRad2Deg(mathAtan2(e.y - s.y, e.x - s.x)); auto angle = mathDeg2Rad((startAngle + this->angle(frameNo, exps))); auto fx = s.x + cos(angle) * progress * r; auto fy = s.y + sin(angle) * progress * r; diff --git a/src/loaders/lottie/tvgLottieProperty.h b/src/loaders/lottie/tvgLottieProperty.h index 810091dd..f77549b3 100644 --- a/src/loaders/lottie/tvgLottieProperty.h +++ b/src/loaders/lottie/tvgLottieProperty.h @@ -156,7 +156,7 @@ struct LottieVectorFrame { if (!hasTangent) { Point dp = next->value - value; - return mathRad2Deg(atan2(dp.y, dp.x)); + return mathRad2Deg(mathAtan2(dp.y, dp.x)); } auto t = (frameNo - no) / (next->no - no); diff --git a/src/loaders/svg/tvgSvgPath.cpp b/src/loaders/svg/tvgSvgPath.cpp index a25d4239..c6ed978d 100644 --- a/src/loaders/svg/tvgSvgPath.cpp +++ b/src/loaders/svg/tvgSvgPath.cpp @@ -194,10 +194,10 @@ void _pathAppendArcTo(Array* cmds, Array* pts, Point* cur, P //We dont' use arccos (as per w3c doc), see //http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm //Note: atan2 (0.0, 1.0) == 0.0 - at = atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx)); + at = mathAtan2(((y1p - cyp) / ry), ((x1p - cxp) / rx)); theta1 = (at < 0.0f) ? 2.0f * MATH_PI + at : at; - nat = atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx)); + nat = mathAtan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx)); deltaTheta = (nat < at) ? 2.0f * MATH_PI - at + nat : nat - at; if (sweep) { diff --git a/src/renderer/gl_engine/tvgGlTessellator.cpp b/src/renderer/gl_engine/tvgGlTessellator.cpp index e75dc9a4..7069ab0d 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.cpp +++ b/src/renderer/gl_engine/tvgGlTessellator.cpp @@ -20,6 +20,7 @@ * SOFTWARE. */ +#include "tvgMath.h" #include "tvgGlTessellator.h" #include "tvgRender.h" #include "tvgGlList.h" @@ -780,7 +781,7 @@ static int32_t _bezierCurveCount(const Bezier &curve) static Bezier _bezFromArc(const GlPoint& start, const GlPoint& end, float radius) { // Calculate the angle between the start and end points - float angle = atan2(end.y - start.y, end.x - start.x); + float angle = mathAtan2(end.y - start.y, end.x - start.x); // Calculate the control points of the cubic bezier curve float c = radius * 0.552284749831; // c = radius * (4/3) * tan(pi/8) diff --git a/src/renderer/sw_engine/tvgSwMath.cpp b/src/renderer/sw_engine/tvgSwMath.cpp index 656d16e9..b48be7a7 100644 --- a/src/renderer/sw_engine/tvgSwMath.cpp +++ b/src/renderer/sw_engine/tvgSwMath.cpp @@ -179,7 +179,7 @@ SwFixed mathTan(SwFixed angle) SwFixed mathAtan(const SwPoint& pt) { if (pt.zero()) return 0; - return SwFixed(atan2f(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f); + return SwFixed(mathAtan2(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f); }