diff options
author | reed <reed@chromium.org> | 2015-04-15 18:23:03 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-15 18:23:03 -0700 |
commit | 6983f66d8b3a489133b751e2cef03e72a03bfeae (patch) | |
tree | 1c6b10b05372664f53eb0117ba0d41770ccdc197 /src/core/SkScan_Hairline.cpp | |
parent | a12225bd32d5172d0d07a7b6c75652f758dbb001 (diff) |
Speeup hairline curves (quads and cubics) (patchset #7 id:120001 of https://codereview.chromium.org/1078413003/)"
ah ha! Check for the define *after* we pull in SkUserConfig.h (indirectly)
This reverts commit 639a82855b94b93c4fa45560e67df8ec4a8bbb3a.
BUG=skia:
TBR=
Review URL: https://codereview.chromium.org/1084283003
Diffstat (limited to 'src/core/SkScan_Hairline.cpp')
-rw-r--r-- | src/core/SkScan_Hairline.cpp | 134 |
1 files changed, 126 insertions, 8 deletions
diff --git a/src/core/SkScan_Hairline.cpp b/src/core/SkScan_Hairline.cpp index 0f2308b1f7..2ec051f8ab 100644 --- a/src/core/SkScan_Hairline.cpp +++ b/src/core/SkScan_Hairline.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #include "SkScan.h" #include "SkBlitter.h" #include "SkRasterClip.h" @@ -192,6 +190,10 @@ void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip, #include "SkPath.h" #include "SkGeometry.h" +#include "SkNx.h" + +#define kMaxCubicSubdivideLevel 6 +#define kMaxQuadSubdivideLevel 5 static int compute_int_quad_dist(const SkPoint pts[3]) { // compute the vector between the control point ([1]) and the middle of the @@ -214,6 +216,9 @@ static int compute_int_quad_dist(const SkPoint pts[3]) { static void hairquad(const SkPoint pts[3], const SkRegion* clip, SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc) { + SkASSERT(level <= kMaxQuadSubdivideLevel); + +#ifdef SK_SUPPORT_LEGACY_BLITANTIH2V2 if (level > 0) { SkPoint tmp[5]; @@ -224,10 +229,113 @@ static void hairquad(const SkPoint pts[3], const SkRegion* clip, SkPoint tmp[] = { pts[0], pts[2] }; lineproc(tmp, 2, clip, blitter); } +#else + SkPoint coeff[3]; + SkQuadToCoeff(pts, coeff); + + const int lines = 1 << level; + Sk2s t(0); + Sk2s dt(SK_Scalar1 / lines); + + SkPoint tmp[(1 << kMaxQuadSubdivideLevel) + 1]; + 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); + for (int i = 1; i < lines; ++i) { + t += dt; + ((A * t + B) * t + C).store(&tmp[i].fX); + } + tmp[lines] = pts[2]; + lineproc(tmp, lines + 1, clip, blitter); +#endif } -static void haircubic(const SkPoint pts[4], const SkRegion* clip, +#ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2 +static inline Sk2s abs(const Sk2s& value) { + return Sk2s::Max(value, -value); +} + +static inline SkScalar max_component(const Sk2s& value) { + SkScalar components[2]; + value.store(components); + return SkTMax(components[0], components[1]); +} + +static inline int compute_cubic_segs(const SkPoint pts[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 oneThird(1.0f / 3.0f); + const Sk2s twoThird(2.0f / 3.0f); + + Sk2s p13 = oneThird * p3 + twoThird * p0; + Sk2s p23 = oneThird * p0 + twoThird * p3; + + SkScalar diff = max_component(Sk2s::Max(abs(p1 - p13), abs(p2 - p23))); + SkScalar tol = SK_Scalar1 / 8; + + for (int i = 0; i < kMaxCubicSubdivideLevel; ++i) { + if (diff < tol) { + return 1 << i; + } + tol *= 4; + } + return 1 << kMaxCubicSubdivideLevel; +} + +static bool lt_90(SkPoint p0, SkPoint pivot, SkPoint p2) { + return SkVector::DotProduct(p0 - pivot, p2 - pivot) >= 0; +} + +// The off-curve points are "inside" the limits of the on-curve pts +static bool quick_cubic_niceness_check(const SkPoint pts[4]) { + return lt_90(pts[1], pts[0], pts[3]) && + lt_90(pts[2], pts[0], pts[3]) && + lt_90(pts[1], pts[3], pts[0]) && + lt_90(pts[2], pts[3], pts[0]); +} + +static void hair_cubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* blitter, + SkScan::HairRgnProc lineproc) { + const int lines = compute_cubic_segs(pts); + SkASSERT(lines > 0); + if (1 == lines) { + SkPoint tmp[2] = { pts[0], pts[3] }; + lineproc(tmp, 2, clip, blitter); + return; + } + + SkPoint coeff[4]; + SkCubicToCoeff(pts, coeff); + + const Sk2s dt(SK_Scalar1 / lines); + Sk2s t(0); + + SkPoint tmp[(1 << kMaxCubicSubdivideLevel) + 1]; + 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); + for (int i = 1; i < lines; ++i) { + t += dt; + (((A * t + B) * t + C) * t + D).store(&tmp[i].fX); + } + tmp[lines] = pts[3]; + lineproc(tmp, lines + 1, clip, blitter); +} +#endif + +static inline void haircubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* blitter, int level, SkScan::HairRgnProc lineproc) { +#ifdef SK_SUPPORT_LEGACY_BLITANTIH2V2 if (level > 0) { SkPoint tmp[7]; @@ -238,10 +346,20 @@ static void haircubic(const SkPoint pts[4], const SkRegion* clip, SkPoint tmp[] = { pts[0], pts[3] }; lineproc(tmp, 2, clip, blitter); } -} +#else + if (quick_cubic_niceness_check(pts)) { + hair_cubic(pts, clip, blitter, lineproc); + } else { + SkPoint tmp[13]; + SkScalar tValues[3]; -#define kMaxCubicSubdivideLevel 6 -#define kMaxQuadSubdivideLevel 5 + int count = SkChopCubicAtMaxCurvature(pts, tmp, tValues); + for (int i = 0; i < count; i++) { + hair_cubic(&tmp[i * 3], clip, blitter, lineproc); + } + } +#endif +} static int compute_quad_level(const SkPoint pts[3]) { int d = compute_int_quad_dist(pts); @@ -311,9 +429,9 @@ static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* } break; } - case SkPath::kCubic_Verb: + case SkPath::kCubic_Verb: { haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc); - break; + } break; case SkPath::kClose_Verb: break; case SkPath::kDone_Verb: |