move more geometry to simd

Remove duplicate quad and cubic code around
computing the polynomial coefficients, and
use common SIMD-based code instead.

R=reed@google.com
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1633143002

Review URL: https://codereview.chromium.org/1633143002
This commit is contained in:
caryclark 2016-01-26 17:02:30 -08:00 committed by Commit bot
parent 727b7d27af
commit 5ba2b9612a
4 changed files with 52 additions and 169 deletions

View File

@ -104,44 +104,12 @@ int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) {
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static Sk2s quad_poly_eval(const Sk2s& A, const Sk2s& B, const Sk2s& C, const Sk2s& t) {
return (A * t + B) * t + C;
}
static SkScalar eval_quad(const SkScalar src[], SkScalar t) {
SkASSERT(src);
SkASSERT(t >= 0 && t <= SK_Scalar1);
#ifdef DIRECT_EVAL_OF_POLYNOMIALS
SkScalar C = src[0];
SkScalar A = src[4] - 2 * src[2] + C;
SkScalar B = 2 * (src[2] - C);
return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
#else
SkScalar ab = SkScalarInterp(src[0], src[2], t);
SkScalar bc = SkScalarInterp(src[2], src[4], t);
return SkScalarInterp(ab, bc, t);
#endif
}
void SkQuadToCoeff(const SkPoint pts[3], SkPoint coeff[3]) {
Sk2s p0 = from_point(pts[0]);
Sk2s p1 = from_point(pts[1]);
Sk2s p2 = from_point(pts[2]);
Sk2s p1minus2 = p1 - p0;
coeff[0] = to_point(p2 - p1 - p1 + p0); // A * t^2
coeff[1] = to_point(p1minus2 + p1minus2); // B * t
coeff[2] = pts[0]; // C
}
void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent) {
SkASSERT(src);
SkASSERT(t >= 0 && t <= SK_Scalar1);
if (pt) {
pt->set(eval_quad(&src[0].fX, t), eval_quad(&src[0].fY, t));
*pt = SkEvalQuadAt(src, t);
}
if (tangent) {
*tangent = SkEvalQuadTangentAt(src, t);
@ -149,19 +117,7 @@ void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tange
}
SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) {
SkASSERT(src);
SkASSERT(t >= 0 && t <= SK_Scalar1);
const Sk2s t2(t);
Sk2s P0 = from_point(src[0]);
Sk2s P1 = from_point(src[1]);
Sk2s P2 = from_point(src[2]);
Sk2s B = P1 - P0;
Sk2s A = P2 - P1 - B;
return to_point((A * t2 + B+B) * t2 + P0);
return to_point(SkQuadCoeff(src).eval(t));
}
SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) {
@ -333,6 +289,7 @@ void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4]) {
///// CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS /////
//////////////////////////////////////////////////////////////////////////////
#ifdef SK_SUPPORT_LEGACY_EVAL_CUBIC
static SkScalar eval_cubic(const SkScalar src[], SkScalar t) {
SkASSERT(src);
SkASSERT(t >= 0 && t <= SK_Scalar1);
@ -357,28 +314,30 @@ static SkScalar eval_cubic(const SkScalar src[], SkScalar t) {
return SkScalarInterp(abc, bcd, t);
#endif
}
#endif
/** return At^2 + Bt + C
*/
static SkScalar eval_quadratic(SkScalar A, SkScalar B, SkScalar C, SkScalar t) {
SkASSERT(t >= 0 && t <= SK_Scalar1);
static SkVector eval_cubic_derivative(const SkPoint src[4], SkScalar t) {
SkQuadCoeff coeff;
Sk2s P0 = from_point(src[0]);
Sk2s P1 = from_point(src[1]);
Sk2s P2 = from_point(src[2]);
Sk2s P3 = from_point(src[3]);
return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
coeff.fA = P3 + Sk2s(3) * (P1 - P2) - P0;
coeff.fB = times_2(P2 - times_2(P1) + P0);
coeff.fC = P1 - P0;
return to_vector(coeff.eval(t));
}
static SkScalar eval_cubic_derivative(const SkScalar src[], SkScalar t) {
SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
SkScalar B = 2*(src[4] - 2 * src[2] + src[0]);
SkScalar C = src[2] - src[0];
static SkVector eval_cubic_2ndDerivative(const SkPoint src[4], SkScalar t) {
Sk2s P0 = from_point(src[0]);
Sk2s P1 = from_point(src[1]);
Sk2s P2 = from_point(src[2]);
Sk2s P3 = from_point(src[3]);
Sk2s A = P3 + Sk2s(3) * (P1 - P2) - P0;
Sk2s B = P2 - times_2(P1) + P0;
return eval_quadratic(A, B, C, t);
}
static SkScalar eval_cubic_2ndDerivative(const SkScalar src[], SkScalar t) {
SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
SkScalar B = src[4] - 2 * src[2] + src[0];
return SkScalarMulAdd(A, t, B);
return to_vector(A * Sk2s(t) + B);
}
void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc,
@ -387,7 +346,11 @@ void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc,
SkASSERT(t >= 0 && t <= SK_Scalar1);
if (loc) {
#ifdef SK_SUPPORT_LEGACY_EVAL_CUBIC
loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t));
#else
*loc = to_point(SkCubicCoeff(src).eval(t));
#endif
}
if (tangent) {
// The derivative equation returns a zero tangent vector when t is 0 or 1, and the
@ -403,13 +366,11 @@ void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc,
*tangent = src[3] - src[0];
}
} else {
tangent->set(eval_cubic_derivative(&src[0].fX, t),
eval_cubic_derivative(&src[0].fY, t));
*tangent = eval_cubic_derivative(src, t);
}
}
if (curvature) {
curvature->set(eval_cubic_2ndDerivative(&src[0].fX, t),
eval_cubic_2ndDerivative(&src[0].fY, t));
*curvature = eval_cubic_2ndDerivative(src, t);
}
}
@ -454,26 +415,6 @@ void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t) {
dst[6] = src[3];
}
void SkCubicToCoeff(const SkPoint pts[4], SkPoint coeff[4]) {
Sk2s p0 = from_point(pts[0]);
Sk2s p1 = from_point(pts[1]);
Sk2s p2 = from_point(pts[2]);
Sk2s p3 = from_point(pts[3]);
const Sk2s three(3);
Sk2s p1minusp2 = p1 - p2;
Sk2s D = p0;
Sk2s A = p3 + three * p1minusp2 - D;
Sk2s B = three * (D - p1minusp2 - p1);
Sk2s C = three * (p1 - D);
coeff[0] = to_point(A);
coeff[1] = to_point(B);
coeff[2] = to_point(C);
coeff[3] = to_point(D);
}
/* http://code.google.com/p/skia/issues/detail?id=32
This test code would fail when we didn't check the return result of
@ -1092,24 +1033,7 @@ void SkConic::chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const {
}
SkPoint SkConic::evalAt(SkScalar t) const {
Sk2s p0 = from_point(fPts[0]);
Sk2s p1 = from_point(fPts[1]);
Sk2s p2 = from_point(fPts[2]);
Sk2s tt(t);
Sk2s ww(fW);
Sk2s one(1);
Sk2s p1w = p1 * ww;
Sk2s C = p0;
Sk2s A = p2 - times_2(p1w) + p0;
Sk2s B = times_2(p1w - C);
Sk2s numer = quad_poly_eval(A, B, C, tt);
B = times_2(ww - one);
A = Sk2s(0)-B;
Sk2s denom = quad_poly_eval(A, B, one, tt);
return to_point(numer / denom);
return to_point(SkConicCoeff(*this).eval(t));
}
SkVector SkConic::evalTangentAt(SkScalar t) const {
@ -1131,7 +1055,7 @@ SkVector SkConic::evalTangentAt(SkScalar t) const {
Sk2s A = ww * p20 - p20;
Sk2s B = p20 - C - C;
return to_vector(quad_poly_eval(A, B, C, Sk2s(t)));
return to_vector(SkQuadCoeff(A, B, C).eval(t));
}
void SkConic::evalAt(SkScalar t, SkPoint* pt, SkVector* tangent) const {
@ -1149,10 +1073,6 @@ static SkScalar subdivide_w_value(SkScalar w) {
return SkScalarSqrt(SK_ScalarHalf + w * SK_ScalarHalf);
}
static Sk2s twice(const Sk2s& value) {
return value + value;
}
void SkConic::chop(SkConic * SK_RESTRICT dst) const {
Sk2s scale = Sk2s(SkScalarInvert(SK_Scalar1 + fW));
SkScalar newW = subdivide_w_value(fW);
@ -1163,7 +1083,7 @@ void SkConic::chop(SkConic * SK_RESTRICT dst) const {
Sk2s ww(fW);
Sk2s wp1 = ww * p1;
Sk2s m = (p0 + twice(wp1) + p2) * scale * Sk2s(0.5f);
Sk2s m = (p0 + times_2(wp1) + p2) * scale * Sk2s(0.5f);
dst[0].fPts[0] = fPts[0];
dst[0].fPts[1] = to_point((p0 + wp1) * scale);

View File

@ -21,11 +21,6 @@ static inline SkPoint to_point(const Sk2s& x) {
return point;
}
static inline Sk2s sk2s_cubic_eval(const Sk2s& A, const Sk2s& B, const Sk2s& C, const Sk2s& D,
const Sk2s& t) {
return ((A * t + B) * t + C) * t + D;
}
static Sk2s times_2(const Sk2s& value) {
return value + value;
}
@ -45,16 +40,6 @@ SkPoint SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t);
*/
void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent = nullptr);
/**
* output is : eval(t) == coeff[0] * t^2 + coeff[1] * t + coeff[2]
*/
void SkQuadToCoeff(const SkPoint pts[3], SkPoint coeff[3]);
/**
* output is : eval(t) == coeff[0] * t^3 + coeff[1] * t^2 + coeff[2] * t + coeff[3]
*/
void SkCubicToCoeff(const SkPoint pts[4], SkPoint coeff[4]);
/** Given a src quadratic bezier, chop it at the specified t value,
where 0 < t < 1, and return the two new quadratics in dst:
dst[0..2] and dst[2..4]

View File

@ -218,8 +218,7 @@ static void hairquad(const SkPoint pts[3], const SkRegion* clip,
SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc) {
SkASSERT(level <= kMaxQuadSubdivideLevel);
SkPoint coeff[3];
SkQuadToCoeff(pts, coeff);
SkQuadCoeff coeff(pts);
const int lines = 1 << level;
Sk2s t(0);
@ -229,9 +228,9 @@ static void hairquad(const SkPoint pts[3], const SkRegion* clip,
SkASSERT((unsigned)lines < SK_ARRAY_COUNT(tmp));
tmp[0] = pts[0];
Sk2s A = Sk2s::Load(&coeff[0].fX);
Sk2s B = Sk2s::Load(&coeff[1].fX);
Sk2s C = Sk2s::Load(&coeff[2].fX);
Sk2s A = coeff.fA;
Sk2s B = coeff.fB;
Sk2s C = coeff.fC;
for (int i = 1; i < lines; ++i) {
t = t + dt;
((A * t + B) * t + C).store(&tmp[i].fX);
@ -296,8 +295,7 @@ static void hair_cubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* bl
return;
}
SkPoint coeff[4];
SkCubicToCoeff(pts, coeff);
SkCubicCoeff coeff(pts);
const Sk2s dt(SK_Scalar1 / lines);
Sk2s t(0);
@ -306,10 +304,10 @@ static void hair_cubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* bl
SkASSERT((unsigned)lines < SK_ARRAY_COUNT(tmp));
tmp[0] = pts[0];
Sk2s A = Sk2s::Load(&coeff[0].fX);
Sk2s B = Sk2s::Load(&coeff[1].fX);
Sk2s C = Sk2s::Load(&coeff[2].fX);
Sk2s D = Sk2s::Load(&coeff[3].fX);
Sk2s A = coeff.fA;
Sk2s B = coeff.fB;
Sk2s C = coeff.fC;
Sk2s D = coeff.fD;
for (int i = 1; i < lines; ++i) {
t = t + dt;
(((A * t + B) * t + C) * t + D).store(&tmp[i].fX);

View File

@ -30,34 +30,15 @@
class FwDCubicEvaluator {
public:
FwDCubicEvaluator()
: fMax(0)
, fCurrent(0)
, fDivisions(0) {
memset(fPoints, 0, 4 * sizeof(SkPoint));
memset(fPoints, 0, 4 * sizeof(SkPoint));
memset(fPoints, 0, 4 * sizeof(SkPoint));
}
/**
* Receives the 4 control points of the cubic bezier.
*/
FwDCubicEvaluator(SkPoint a, SkPoint b, SkPoint c, SkPoint d) {
fPoints[0] = a;
fPoints[1] = b;
fPoints[2] = c;
fPoints[3] = d;
SkCubicToCoeff(fPoints, fCoefs);
this->restart(1);
}
explicit FwDCubicEvaluator(const SkPoint points[4]) {
explicit FwDCubicEvaluator(const SkPoint points[4])
: fCoefs(points) {
memcpy(fPoints, points, 4 * sizeof(SkPoint));
SkCubicToCoeff(fPoints, fCoefs);
this->restart(1);
}
@ -66,18 +47,16 @@ public:
*/
void restart(int divisions) {
fDivisions = divisions;
SkScalar h = 1.f / fDivisions;
fCurrent = 0;
fMax = fDivisions + 1;
fFwDiff[0] = fCoefs[3];
SkScalar h2 = h * h;
SkScalar h3 = h2 * h;
fFwDiff[3].set(6.f * fCoefs[0].x() * h3, 6.f * fCoefs[0].y() * h3); //6ah^3
fFwDiff[2].set(fFwDiff[3].x() + 2.f * fCoefs[1].x() * h2, //6ah^3 + 2bh^2
fFwDiff[3].y() + 2.f * fCoefs[1].y() * h2);
fFwDiff[1].set(fCoefs[0].x() * h3 + fCoefs[1].x() * h2 + fCoefs[2].x() * h,//ah^3 + bh^2 +ch
fCoefs[0].y() * h3 + fCoefs[1].y() * h2 + fCoefs[2].y() * h);
Sk2s h = Sk2s(1.f / fDivisions);
Sk2s h2 = h * h;
Sk2s h3 = h2 * h;
Sk2s fwDiff3 = Sk2s(6) * fCoefs.fA * h3;
fFwDiff[3] = to_point(fwDiff3);
fFwDiff[2] = to_point(fwDiff3 + times_2(fCoefs.fB) * h2);
fFwDiff[1] = to_point(fCoefs.fA * h3 + fCoefs.fB * h2 + fCoefs.fC * h);
fFwDiff[0] = to_point(fCoefs.fD);
}
/**
@ -104,8 +83,9 @@ public:
}
private:
SkCubicCoeff fCoefs;
int fMax, fCurrent, fDivisions;
SkPoint fFwDiff[4], fCoefs[4], fPoints[4];
SkPoint fFwDiff[4], fPoints[4];
};
////////////////////////////////////////////////////////////////////////////////