diff options
Diffstat (limited to 'src/core/SkScan_AntiPath.cpp')
-rw-r--r-- | src/core/SkScan_AntiPath.cpp | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index ad181a77f8..ab86b4e7d9 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -12,6 +12,7 @@ #include "SkBlitter.h" #include "SkRegion.h" #include "SkAntiRun.h" +#include "SkCoverageDelta.h" #define SHIFT SK_SUPERSAMPLE_SHIFT #define SCALE (1 << SHIFT) @@ -583,6 +584,19 @@ void MaskSuperBlitter::blitH(int x, int y, int width) { /////////////////////////////////////////////////////////////////////////////// +static SkIRect safeRoundOut(const SkRect& src) { + // roundOut will pin huge floats to max/min int + SkIRect dst = src.roundOut(); + + // intersect with a smaller huge rect, so the rect will not be considered empty for being + // too large. e.g. { -SK_MaxS32 ... SK_MaxS32 } is considered empty because its width + // exceeds signed 32bit. + const int32_t limit = SK_MaxS32 >> SK_SUPERSAMPLE_SHIFT; + (void)dst.intersect({ -limit, -limit, limit, limit}); + + return dst; +} + static bool ShouldUseDAA(const SkPath& path) { if (gSkForceDeltaAA) { return true; @@ -597,12 +611,18 @@ static bool ShouldUseDAA(const SkPath& path) { #else constexpr int kSampleSize = 8; constexpr SkScalar kComplexityThreshold = 0.25; + constexpr SkScalar kSmallCubicThreshold = 16; int n = path.countPoints(); - if (path.isConvex() || n < kSampleSize) { + if (path.isConvex() || n < kSampleSize || path.getBounds().isEmpty()) { return false; } + // DAA is fast with mask + if (SkCoverageDeltaMask::CanHandle(safeRoundOut(path.getBounds()))) { + return true; + } + SkScalar sumLength = 0; SkPoint lastPoint = path.getPoint(0); for(int i = 1; i < kSampleSize; ++i) { @@ -610,11 +630,27 @@ static bool ShouldUseDAA(const SkPath& path) { sumLength += SkPoint::Distance(lastPoint, point); lastPoint = point; } + SkScalar avgLength = sumLength / (kSampleSize - 1); + + // DAA is much faster in small cubics (since we don't have to chop them). + // If there are many cubics, and the average length if small, use DAA. + if (avgLength < kSmallCubicThreshold) { + uint8_t sampleVerbs[kSampleSize]; + int verbCount = SkTMin(kSampleSize, path.getVerbs(sampleVerbs, kSampleSize)); + int cubicCount = 0; + for(int i = 0; i < verbCount; ++i) { + cubicCount += (sampleVerbs[i] == SkPath::kCubic_Verb); + } + if (cubicCount * 2 >= verbCount) { + return true; + } + } + SkScalar diagonal = SkPoint::Length(path.getBounds().width(), path.getBounds().height()); // On average, what's the distance between two consecutive points; the number is normalized // to a range of [0, 1] where 1 corresponds to the maximum length of the diagonal. - SkScalar sampleSpan = sumLength / (kSampleSize - 1) / diagonal; + SkScalar sampleSpan = avgLength / diagonal; // If the path is consist of random line segments, the number of intersections should be @@ -687,19 +723,6 @@ static int rect_overflows_short_shift(SkIRect rect, int shift) { overflows_short_shift(rect.fBottom, shift); } -static SkIRect safeRoundOut(const SkRect& src) { - // roundOut will pin huge floats to max/min int - SkIRect dst = src.roundOut(); - - // intersect with a smaller huge rect, so the rect will not be considered empty for being - // too large. e.g. { -SK_MaxS32 ... SK_MaxS32 } is considered empty because its width - // exceeds signed 32bit. - const int32_t limit = SK_MaxS32 >> SK_SUPERSAMPLE_SHIFT; - (void)dst.intersect({ -limit, -limit, limit, limit}); - - return dst; -} - void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter, bool forceRLE, SkDAARecord* daaRecord) { if (origClip.isEmpty()) { |