diff options
-rw-r--r-- | bench/nanobench.cpp | 4 | ||||
-rw-r--r-- | dm/DM.cpp | 4 | ||||
-rw-r--r-- | samplecode/SampleApp.cpp | 13 | ||||
-rw-r--r-- | src/core/SkAnalyticEdge.cpp | 104 | ||||
-rw-r--r-- | src/core/SkAnalyticEdge.h | 86 | ||||
-rw-r--r-- | src/core/SkScan.cpp | 2 | ||||
-rw-r--r-- | src/core/SkScan.h | 4 | ||||
-rw-r--r-- | src/core/SkScanPriv.h | 4 | ||||
-rw-r--r-- | src/core/SkScan_AAAPath.cpp | 669 | ||||
-rw-r--r-- | src/core/SkScan_AntiPath.cpp | 20 | ||||
-rw-r--r-- | tools/flags/SkCommonFlags.cpp | 4 | ||||
-rw-r--r-- | tools/flags/SkCommonFlags.h | 1 |
12 files changed, 157 insertions, 758 deletions
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp index 7e053198e4..34aaee8dd0 100644 --- a/bench/nanobench.cpp +++ b/bench/nanobench.cpp @@ -1198,10 +1198,6 @@ int nanobench_main() { gSkUseAnalyticAA = FLAGS_analyticAA; - if (FLAGS_forceAnalyticAA) { - gSkForceAnalyticAA = true; - } - int runs = 0; BenchmarkStream benchStream; while (Benchmark* b = benchStream.next()) { @@ -1289,10 +1289,6 @@ int dm_main() { gSkUseAnalyticAA = FLAGS_analyticAA; - if (FLAGS_forceAnalyticAA) { - gSkForceAnalyticAA = true; - } - if (FLAGS_verbose) { gVLog = stderr; } else if (!FLAGS_writePath.isEmpty()) { diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index a1dabc2f65..8797c4d5ca 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -1822,12 +1822,7 @@ bool SampleWindow::onHandleChar(SkUnichar uni) { } break; case 'A': - if (gSkUseAnalyticAA.load() && !gSkForceAnalyticAA.load()) { - gSkForceAnalyticAA = true; - } else { - gSkUseAnalyticAA = !gSkUseAnalyticAA.load(); - gSkForceAnalyticAA = false; - } + gSkUseAnalyticAA = !gSkUseAnalyticAA.load(); this->inval(nullptr); this->updateTitle(); break; @@ -2181,11 +2176,7 @@ void SampleWindow::updateTitle() { title.prepend(gDeviceTypePrefix[fDeviceType]); if (gSkUseAnalyticAA) { - if (gSkForceAnalyticAA) { - title.prepend("<FAAA> "); - } else { - title.prepend("<AAA> "); - } + title.prepend("<AAA> "); } if (fTilingMode != kNo_Tiling) { title.prependf("<T: %s> ", gTilingInfo[fTilingMode].label); diff --git a/src/core/SkAnalyticEdge.cpp b/src/core/SkAnalyticEdge.cpp index 199fc4ef33..057bc2170a 100644 --- a/src/core/SkAnalyticEdge.cpp +++ b/src/core/SkAnalyticEdge.cpp @@ -48,22 +48,34 @@ bool SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1, return true; } -bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) { - fRiteE = nullptr; +void SkAnalyticEdge::chopLineWithClip(const SkIRect& clip) { + int top = SkFixedFloorToInt(fUpperY); + + SkASSERT(top < clip.fBottom); - if (!fQEdge.setQuadraticWithoutUpdate(pts, kDefaultAccuracy)) { + // clip the line to the clip top + if (top < clip.fTop) { + SkASSERT(SkFixedCeilToInt(fLowerY) > clip.fTop); + SkFixed newY = SkIntToFixed(clip.fTop); + this->goY(newY); + fUpperY = newY; + } +} + +bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) { + if (!fQEdge.setQuadraticWithoutUpdate(pts, 2)) { return false; } - fQEdge.fQx >>= kDefaultAccuracy; - fQEdge.fQy >>= kDefaultAccuracy; - fQEdge.fQDx >>= kDefaultAccuracy; - fQEdge.fQDy >>= kDefaultAccuracy; - fQEdge.fQDDx >>= kDefaultAccuracy; - fQEdge.fQDDy >>= kDefaultAccuracy; - fQEdge.fQLastX >>= kDefaultAccuracy; - fQEdge.fQLastY >>= kDefaultAccuracy; - fQEdge.fQy = SnapY(fQEdge.fQy); - fQEdge.fQLastY = SnapY(fQEdge.fQLastY); + fQEdge.fQx >>= 2; + fQEdge.fQy >>= 2; + fQEdge.fQDx >>= 2; + fQEdge.fQDy >>= 2; + fQEdge.fQDDx >>= 2; + fQEdge.fQDDy >>= 2; + fQEdge.fQLastX >>= 2; + fQEdge.fQLastY >>= 2; + fQEdge.fQy = snapY(fQEdge.fQy); + fQEdge.fQLastY = snapY(fQEdge.fQLastY); fWinding = fQEdge.fWinding; fCurveCount = fQEdge.fCurveCount; @@ -93,28 +105,15 @@ bool SkAnalyticQuadraticEdge::updateQuadratic() { { newx = oldx + (dx >> shift); newy = oldy + (dy >> shift); + SkFDot6 diffY = (newy - fSnappedY) >> 10; + slope = diffY ? QuickSkFDot6Div((newx - fSnappedX) >> 10, diffY) : SK_MaxS32; if (SkAbs32(dy >> shift) >= SK_Fixed1 * 2) { // only snap when dy is large enough - SkFDot6 diffY = SkFixedToFDot6(newy - fSnappedY); - slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY) - : SK_MaxS32; newSnappedY = SkTMin<SkFixed>(fQEdge.fQLastY, SkFixedRoundToFixed(newy)); newSnappedX = newx - SkFixedMul(slope, newy - newSnappedY); } else { - newSnappedY = SkTMin(fQEdge.fQLastY, SnapY(newy)); + newSnappedY = SkTMin(fQEdge.fQLastY, snapY(newy)); newSnappedX = newx; -#ifdef SK_SUPPORT_LEGACY_AAA - SkFDot6 diffY = SkFixedToFDot6(newy - fSnappedY); -#else - SkFDot6 diffY = SkFixedToFDot6(newSnappedY - fSnappedY); -#endif - slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY) - : SK_MaxS32; } -#ifndef SK_SUPPORT_LEGACY_AAA - SkASSERT(slope == SK_MaxS32 || - SkAbs32(fSnappedX + SkFixedMul(slope, newSnappedY - fSnappedY) - newSnappedX) - < SK_FixedHalf); -#endif dx += fQEdge.fQDDx; dy += fQEdge.fQDDy; } @@ -147,32 +146,28 @@ bool SkAnalyticQuadraticEdge::updateQuadratic() { } bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4]) { - fRiteE = nullptr; - - if (!fCEdge.setCubicWithoutUpdate(pts, kDefaultAccuracy)) { + if (!fCEdge.setCubicWithoutUpdate(pts, 2)) { return false; } - fCEdge.fCx >>= kDefaultAccuracy; - fCEdge.fCy >>= kDefaultAccuracy; - fCEdge.fCDx >>= kDefaultAccuracy; - fCEdge.fCDy >>= kDefaultAccuracy; - fCEdge.fCDDx >>= kDefaultAccuracy; - fCEdge.fCDDy >>= kDefaultAccuracy; - fCEdge.fCDDDx >>= kDefaultAccuracy; - fCEdge.fCDDDy >>= kDefaultAccuracy; - fCEdge.fCLastX >>= kDefaultAccuracy; - fCEdge.fCLastY >>= kDefaultAccuracy; - fCEdge.fCy = SnapY(fCEdge.fCy); - fCEdge.fCLastY = SnapY(fCEdge.fCLastY); + fCEdge.fCx >>= 2; + fCEdge.fCy >>= 2; + fCEdge.fCDx >>= 2; + fCEdge.fCDy >>= 2; + fCEdge.fCDDx >>= 2; + fCEdge.fCDDy >>= 2; + fCEdge.fCDDDx >>= 2; + fCEdge.fCDDDy >>= 2; + fCEdge.fCLastX >>= 2; + fCEdge.fCLastY >>= 2; + fCEdge.fCy = snapY(fCEdge.fCy); + fCEdge.fCLastY = snapY(fCEdge.fCLastY); fWinding = fCEdge.fWinding; fCurveCount = fCEdge.fCurveCount; fCurveShift = fCEdge.fCurveShift; fCubicDShift = fCEdge.fCubicDShift; - fSnappedY = fCEdge.fCy; - return this->updateCubic(); } @@ -208,24 +203,17 @@ bool SkAnalyticCubicEdge::updateCubic() { newy = oldy; } - SkFixed newSnappedY = SnapY(newy); - // we want to SkASSERT(snappedNewY <= fCEdge.fCLastY), but our finite fixedpoint - // doesn't always achieve that, so we have to explicitly pin it here. - if (fCEdge.fCLastY < newSnappedY) { - newSnappedY = fCEdge.fCLastY; - count = 0; - } - - SkFixed slope = SkFixedToFDot6(newSnappedY - fSnappedY) == 0 + SkFixed snappedOldY = SkAnalyticEdge::snapY(oldy); + SkFixed snappedNewY = SkAnalyticEdge::snapY(newy); + SkFixed slope = SkFixedToFDot6(snappedNewY - snappedOldY) == 0 ? SK_MaxS32 : SkFDot6Div(SkFixedToFDot6(newx - oldx), - SkFixedToFDot6(newSnappedY - fSnappedY)); + SkFixedToFDot6(snappedNewY - snappedOldY)); - success = this->updateLine(oldx, fSnappedY, newx, newSnappedY, slope); + success = this->updateLine(oldx, snappedOldY, newx, snappedNewY, slope); oldx = newx; oldy = newy; - fSnappedY = newSnappedY; } while (count < 0 && !success); fCEdge.fCx = newx; diff --git a/src/core/SkAnalyticEdge.h b/src/core/SkAnalyticEdge.h index c738b5427b..7f5e62c519 100644 --- a/src/core/SkAnalyticEdge.h +++ b/src/core/SkAnalyticEdge.h @@ -21,10 +21,6 @@ struct SkAnalyticEdge { SkAnalyticEdge* fNext; SkAnalyticEdge* fPrev; - // During aaa_walk_edges, if this edge is a left edge, - // then fRiteE is its corresponding right edge. Otherwise it's nullptr. - SkAnalyticEdge* fRiteE; - SkFixed fX; SkFixed fDX; SkFixed fUpperX; // The x value when y = fUpperY @@ -34,10 +30,6 @@ struct SkAnalyticEdge { SkFixed fDY; // abs(1/fDX); may be SK_MaxS32 when fDX is close to 0. // fDY is only used for blitting trapezoids. - SkFixed fSavedX; // For deferred blitting - SkFixed fSavedY; // For deferred blitting - SkFixed fSavedDY; // For deferred blitting - int8_t fCurveCount; // only used by kQuad(+) and kCubic(-) uint8_t fCurveShift; // appled to all Dx/DDx/DDDx except for fCubicDShift exception uint8_t fCubicDShift; // applied to fCDx and fCDy only in cubic @@ -45,8 +37,7 @@ struct SkAnalyticEdge { static const int kDefaultAccuracy = 2; // default accuracy for snapping - static inline SkFixed SnapY(SkFixed y) { - const int accuracy = kDefaultAccuracy; + static inline SkFixed snapY(SkFixed y, int accuracy = kDefaultAccuracy) { // This approach is safer than left shift, round, then right shift return ((unsigned)y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy); } @@ -64,22 +55,15 @@ struct SkAnalyticEdge { } } - inline void goY(SkFixed y, int yShift) { - SkASSERT(yShift >= 0 && yShift <= kDefaultAccuracy); - SkASSERT(fDX == 0 || y - fY == SK_Fixed1 >> yShift); - fY = y; - fX += fDX >> yShift; - } + inline bool setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip = nullptr); + inline bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope); + void chopLineWithClip(const SkIRect& clip); - inline void saveXY(SkFixed x, SkFixed y, SkFixed dY) { - fSavedX = x; - fSavedY = y; - fSavedDY = dY; + inline bool intersectsClip(const SkIRect& clip) const { + SkASSERT(SkFixedFloorToInt(fUpperY) < clip.fBottom); + return SkFixedCeilToInt(fLowerY) > clip.fTop; } - inline bool setLine(const SkPoint& p0, const SkPoint& p1); - inline bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope); - #ifdef SK_DEBUG void dump() const { SkDebugf("edge: upperY:%d lowerY:%d y:%g x:%g dx:%g w:%d\n", @@ -106,47 +90,36 @@ struct SkAnalyticQuadraticEdge : public SkAnalyticEdge { bool setQuadratic(const SkPoint pts[3]); bool updateQuadratic(); - inline void keepContinuous() { - // We use fX as the starting x to ensure the continuouty. - // Without it, we may break the sorted edge list. - SkASSERT(SkAbs32(fX - SkFixedMul(fY - fSnappedY, fDX) - fSnappedX) < SK_Fixed1); - SkASSERT(SkAbs32(fY - fSnappedY) < SK_Fixed1); // This may differ due to smooth jump - fSnappedX = fX; - fSnappedY = fY; - } }; struct SkAnalyticCubicEdge : public SkAnalyticEdge { SkCubicEdge fCEdge; - SkFixed fSnappedY; // to make sure that y is increasing with smooth jump and snapping - bool setCubic(const SkPoint pts[4]); bool updateCubic(); - inline void keepContinuous() { - SkASSERT(SkAbs32(fX - SkFixedMul(fDX, fY - SnapY(fCEdge.fCy)) - fCEdge.fCx) < SK_Fixed1); - fCEdge.fCx = fX; - fSnappedY = fY; - } }; -bool SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1) { - fRiteE = nullptr; - - // We must set X/Y using the same way (e.g., times 4, to FDot6, then to Fixed) as Quads/Cubics. +bool SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip) { + // We must set X/Y using the same way (times 4, to FDot6, then to Fixed) as Quads/Cubics. // Otherwise the order of the edge might be wrong due to precision limit. - const int accuracy = kDefaultAccuracy; - const int multiplier = (1 << kDefaultAccuracy); - SkFixed x0 = SkFDot6ToFixed(SkScalarToFDot6(p0.fX * multiplier)) >> accuracy; - SkFixed y0 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p0.fY * multiplier)) >> accuracy); - SkFixed x1 = SkFDot6ToFixed(SkScalarToFDot6(p1.fX * multiplier)) >> accuracy; - SkFixed y1 = SnapY(SkFDot6ToFixed(SkScalarToFDot6(p1.fY * multiplier)) >> accuracy); + SkFixed x0 = SkFDot6ToFixed(SkScalarToFDot6(p0.fX * 4)) >> 2; + SkFixed y0 = snapY(SkFDot6ToFixed(SkScalarToFDot6(p0.fY * 4)) >> 2); + SkFixed x1 = SkFDot6ToFixed(SkScalarToFDot6(p1.fX * 4)) >> 2; + SkFixed y1 = snapY(SkFDot6ToFixed(SkScalarToFDot6(p1.fY * 4)) >> 2); // are we a zero-height line? if (y0 == y1) { return false; } + int top = SkFixedFloorToInt(y0); + int bot = SkFixedCeilToInt(y1); + + // are we completely above or below the clip? + if (clip && (top >= clip->fBottom || bot <= clip->fTop)) { + return false; + } + int winding = 1; if (y0 > y1) { @@ -155,15 +128,7 @@ bool SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1) { winding = -1; } -#ifdef SK_SUPPORT_LEGACY_AAA SkFixed slope = SkFixedDiv(x1 - x0, y1 - y0); -#else - SkFDot6 dy = SkFixedToFDot6(y1 - y0); - SkFDot6 dx = SkFixedToFDot6(x1 - x0); - SkFixed slope = dy ? QuickSkFDot6Div(dx, dy) : SK_MaxS32; - SkASSERT(dx == 0 || slope != 0); - SkFixed absSlope = SkAbs32(slope); -#endif fX = x0; fDX = slope; @@ -171,17 +136,14 @@ bool SkAnalyticEdge::setLine(const SkPoint& p0, const SkPoint& p1) { fY = y0; fUpperY = y0; fLowerY = y1; -#ifdef SK_SUPPORT_LEGACY_AAA fDY = x1 != x0 ? SkAbs32(SkFixedDiv(y1 - y0, x1 - x0)) : SK_MaxS32; -#else - fDY = dx == 0 ? SK_MaxS32 : absSlope < kInverseTableSize - ? QuickFDot6Inverse::Lookup(absSlope) - : SkAbs32(QuickSkFDot6Div(dy, dx)); -#endif fCurveCount = 0; fWinding = SkToS8(winding); fCurveShift = 0; + if (clip) { + this->chopLineWithClip(*clip); + } return true; } diff --git a/src/core/SkScan.cpp b/src/core/SkScan.cpp index c2f00f3a84..5a02c61b44 100644 --- a/src/core/SkScan.cpp +++ b/src/core/SkScan.cpp @@ -16,8 +16,6 @@ std::atomic<bool> gSkUseAnalyticAA{true}; #endif -std::atomic<bool> gSkForceAnalyticAA{false}; - static inline void blitrect(SkBlitter* blitter, const SkIRect& r) { blitter->blitRect(r.fLeft, r.fTop, r.width(), r.height()); } diff --git a/src/core/SkScan.h b/src/core/SkScan.h index d4fe48650f..24e008826d 100644 --- a/src/core/SkScan.h +++ b/src/core/SkScan.h @@ -23,11 +23,7 @@ class SkPath; */ typedef SkIRect SkXRect; -// Use this to check that we successfully guard the change against Chromium layout tests -#define SK_SUPPORT_LEGACY_AAA - extern std::atomic<bool> gSkUseAnalyticAA; -extern std::atomic<bool> gSkForceAnalyticAA; class AdditiveBlitter; diff --git a/src/core/SkScanPriv.h b/src/core/SkScanPriv.h index 606929dcdd..4c237e004b 100644 --- a/src/core/SkScanPriv.h +++ b/src/core/SkScanPriv.h @@ -34,6 +34,10 @@ void sk_fill_path(const SkPath& path, const SkIRect& clipRect, SkBlitter* blitter, int start_y, int stop_y, int shiftEdgesUp, bool pathContainedInClip); +void aaa_fill_path(const SkPath& path, const SkIRect& clipRect, AdditiveBlitter*, + int start_y, int stop_y, bool pathContainedInClip, bool isUsingMask, + bool forceRLE); + // blit the rects above and below avoid, clipped to clip void sk_blit_above(SkBlitter*, const SkIRect& avoid, const SkRegion& clip); void sk_blit_below(SkBlitter*, const SkIRect& avoid, const SkRegion& clip); diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp index 126322820f..8c0a748bdf 100644 --- a/src/core/SkScan_AAAPath.cpp +++ b/src/core/SkScan_AAAPath.cpp @@ -84,13 +84,9 @@ number of scan lines in our algorithm is only about 3 + H while the /////////////////////////////////////////////////////////////////////////////// -static inline void addAlpha(SkAlpha* alpha, SkAlpha delta) { - SkASSERT(*alpha + (int)delta <= 256); - *alpha = SkAlphaRuns::CatchOverflow(*alpha + (int)delta); -} - -static inline void safelyAddAlpha(SkAlpha* alpha, SkAlpha delta) { - *alpha = SkTMin(0xFF, *alpha + (int)delta); +static inline void addAlpha(SkAlpha& alpha, SkAlpha delta) { + SkASSERT(alpha + (int)delta <= 256); + alpha = SkAlphaRuns::CatchOverflow(alpha + (int)delta); } class AdditiveBlitter : public SkBlitter { @@ -151,7 +147,7 @@ public: void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; // Allowing following methods are used to blit rectangles during aaa_walk_convex_edges - // Since there aren't many rectangles, we can still bear the slow speed of virtual functions. + // Since there aren't many rectangles, we can still break the slow speed of virtual functions. void blitAntiH(int x, int y, const SkAlpha alpha) override; void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; void blitV(int x, int y, int height, SkAlpha alpha) override; @@ -231,14 +227,14 @@ void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int void MaskAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { SkASSERT(x >= fMask.fBounds.fLeft -1); - addAlpha(&this->getRow(y)[x], alpha); + addAlpha(this->getRow(y)[x], alpha); } void MaskAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { SkASSERT(x >= fMask.fBounds.fLeft -1); uint8_t* row = this->getRow(y); - for (int i = 0; i < width; ++i) { - addAlpha(&row[x + i], alpha); + for (int i=0; i<width; i++) { + addAlpha(row[x + i], alpha); } } @@ -250,7 +246,7 @@ void MaskAdditiveBlitter::blitV(int x, int y, int height, SkAlpha alpha) { // This must be called as if this is a real blitter. // So we directly set alpha rather than adding it. uint8_t* row = this->getRow(y); - for (int i = 0; i < height; ++i) { + for (int i=0; i<height; i++) { row[x] = alpha; row += fMask.fRowBytes; } @@ -261,7 +257,7 @@ void MaskAdditiveBlitter::blitRect(int x, int y, int width, int height) { // This must be called as if this is a real blitter. // So we directly set alpha rather than adding it. uint8_t* row = this->getRow(y); - for (int i = 0; i < height; ++i) { + for (int i=0; i<height; i++) { memset(row + x, 0xFF, width); row += fMask.fRowBytes; } @@ -294,7 +290,7 @@ public: } } -protected: +private: SkBlitter* fRealBlitter; /// Current y coordinate @@ -317,7 +313,7 @@ protected: int fOffsetX; - inline bool check(int x, int width) const { + inline bool check(int x, int width) { #ifdef SK_DEBUG if (x < 0 || x + width > fWidth) { // SkDebugf("Ignore x = %d, width = %d\n", x, width); @@ -435,8 +431,8 @@ void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], } fRuns.fRuns[x + i] = 1; } - for (int i = 0; i < len; ++i) { - addAlpha(&fRuns.fAlpha[x + i], antialias[i]); + for (int i=0; i<len; i++) { + addAlpha(fRuns.fAlpha[x + i], antialias[i]); } } void RunBasedAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { @@ -467,85 +463,12 @@ void RunBasedAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha a int RunBasedAdditiveBlitter::getWidth() { return fWidth; } -// This exists specifically for concave path filling. -// In those cases, we can easily accumulate alpha greater than 0xFF. -class SafeRLEAdditiveBlitter : public RunBasedAdditiveBlitter { -public: - SafeRLEAdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, - bool isInverse) : RunBasedAdditiveBlitter(realBlitter, ir, clip, isInverse) {} - - void blitAntiH(int x, int y, const SkAlpha antialias[], int len) override; - void blitAntiH(int x, int y, const SkAlpha alpha) override; - void blitAntiH(int x, int y, int width, const SkAlpha alpha) override; -}; - -void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], int len) { - checkY(y); - x -= fLeft; - - if (x < 0) { - len += x; - antialias -= x; - x = 0; - } - len = SkTMin(len, fWidth - x); - SkASSERT(check(x, len)); - - if (x < fOffsetX) { - fOffsetX = 0; - } - - fOffsetX = fRuns.add(x, 0, len, 0, 0, fOffsetX); // Break the run - for (int i = 0; i < len; i += fRuns.fRuns[x + i]) { - for (int j = 1; j < fRuns.fRuns[x + i]; j++) { - fRuns.fRuns[x + i + j] = 1; - fRuns.fAlpha[x + i + j] = fRuns.fAlpha[x + i]; - } - fRuns.fRuns[x + i] = 1; - } - for (int i = 0; i < len; ++i) { - safelyAddAlpha(&fRuns.fAlpha[x + i], antialias[i]); - } -} - -void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { - checkY(y); - x -= fLeft; - - if (x < fOffsetX) { - fOffsetX = 0; - } - - if (check(x, 1)) { - // Break the run - fOffsetX = fRuns.add(x, 0, 1, 0, 0, fOffsetX); - safelyAddAlpha(&fRuns.fAlpha[x], alpha); - } -} - -void SafeRLEAdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { - checkY(y); - x -= fLeft; - - if (x < fOffsetX) { - fOffsetX = 0; - } - - if (check(x, width)) { - // Break the run - fOffsetX = fRuns.add(x, 0, width, 0, 0, fOffsetX); - for(int i = x; i < x + width; i += fRuns.fRuns[i]) { - safelyAddAlpha(&fRuns.fAlpha[i], alpha); - } - } -} - /////////////////////////////////////////////////////////////////////////////// // Return the alpha of a trapezoid whose height is 1 static inline SkAlpha trapezoidToAlpha(SkFixed l1, SkFixed l2) { SkASSERT(l1 >= 0 && l2 >= 0); - return (l1 + l2) >> 9; + return ((l1 + l2) >> 9); } // The alpha of right-triangle (a, a*b), in 16 bits @@ -601,7 +524,7 @@ static inline void computeAlphaAboveLine(SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed firstH = SkFixedMul(first, dY); // vertical edge of the left-most triangle alphas[0] = SkFixedMul(first, firstH) >> 9; // triangle alpha SkFixed alpha16 = firstH + (dY >> 1); // rectangle plus triangle - for (int i = 1; i < R - 1; ++i) { + for (int i = 1; i < R - 1; i++) { alphas[i] = alpha16 >> 8; alpha16 += dY; } @@ -634,19 +557,17 @@ static inline void computeAlphaBelowLine( } // Note that if fullAlpha != 0xFF, we'll multiply alpha by fullAlpha -static SK_ALWAYS_INLINE void blit_single_alpha(AdditiveBlitter* blitter, int y, int x, +static inline void blit_single_alpha(AdditiveBlitter* blitter, int y, int x, SkAlpha alpha, SkAlpha fullAlpha, SkAlpha* maskRow, - bool isUsingMask, bool noRealBlitter, bool needSafeCheck) { + bool isUsingMask) { if (isUsingMask) { - if (fullAlpha == 0xFF && !noRealBlitter) { // noRealBlitter is needed for concave paths + if (fullAlpha == 0xFF) { maskRow[x] = alpha; - } else if (needSafeCheck) { - safelyAddAlpha(&maskRow[x], getPartialAlpha(alpha, fullAlpha)); } else { - addAlpha(&maskRow[x], getPartialAlpha(alpha, fullAlpha)); + addAlpha(maskRow[x], getPartialAlpha(alpha, fullAlpha)); } } else { - if (fullAlpha == 0xFF && !noRealBlitter) { + if (fullAlpha == 0xFF) { blitter->getRealBlitter()->blitV(x, y, 1, alpha); } else { blitter->blitAntiH(x, y, getPartialAlpha(alpha, fullAlpha)); @@ -654,19 +575,14 @@ static SK_ALWAYS_INLINE void blit_single_alpha(AdditiveBlitter* blitter, int y, } } -static SK_ALWAYS_INLINE void blit_two_alphas(AdditiveBlitter* blitter, int y, int x, +static inline void blit_two_alphas(AdditiveBlitter* blitter, int y, int x, SkAlpha a1, SkAlpha a2, SkAlpha fullAlpha, SkAlpha* maskRow, - bool isUsingMask, bool noRealBlitter, bool needSafeCheck) { + bool isUsingMask) { if (isUsingMask) { - if (needSafeCheck) { - safelyAddAlpha(&maskRow[x], a1); - safelyAddAlpha(&maskRow[x + 1], a2); - } else { - addAlpha(&maskRow[x], a1); - addAlpha(&maskRow[x + 1], a2); - } + addAlpha(maskRow[x], a1); + addAlpha(maskRow[x + 1], a2); } else { - if (fullAlpha == 0xFF && !noRealBlitter) { + if (fullAlpha == 0xFF) { blitter->getRealBlitter()->blitAntiH2(x, y, a1, a2); } else { blitter->blitAntiH(x, y, a1); @@ -677,18 +593,13 @@ static SK_ALWAYS_INLINE void blit_two_alphas(AdditiveBlitter* blitter, int y, in // It's important that this is inline. Otherwise it'll be much slower. static SK_ALWAYS_INLINE void blit_full_alpha(AdditiveBlitter* blitter, int y, int x, int len, - SkAlpha fullAlpha, SkAlpha* maskRow, bool isUsingMask, - bool noRealBlitter, bool needSafeCheck) { + SkAlpha fullAlpha, SkAlpha* maskRow, bool isUsingMask) { if (isUsingMask) { - for (int i = 0; i < len; ++i) { - if (needSafeCheck) { - safelyAddAlpha(&maskRow[x + i], fullAlpha); - } else { - addAlpha(&maskRow[x + i], fullAlpha); - } + for (int i=0; i<len; i++) { + addAlpha(maskRow[x + i], fullAlpha); } } else { - if (fullAlpha == 0xFF && !noRealBlitter) { + if (fullAlpha == 0xFF) { blitter->getRealBlitter()->blitH(x, y, len); } else { blitter->blitAntiH(x, y, len, fullAlpha); @@ -699,14 +610,13 @@ static SK_ALWAYS_INLINE void blit_full_alpha(AdditiveBlitter* blitter, int y, in static void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, int y, SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, SkAlpha* maskRow, - bool isUsingMask, bool noRealBlitter, bool needSafeCheck) { + bool isUsingMask) { int L = SkFixedFloorToInt(ul), R = SkFixedCeilToInt(lr); int len = R - L; if (len == 1) { SkAlpha alpha = trapezoidToAlpha(ur - ul, lr - ll); - blit_single_alpha(blitter, y, L, alpha, fullAlpha, maskRow, isUsingMask, noRealBlitter, - needSafeCheck); + blit_single_alpha(blitter, y, L, alpha, fullAlpha, maskRow, isUsingMask); return; } @@ -727,7 +637,7 @@ static void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, int y, SkAlpha* tempAlphas = alphas + len + 1; int16_t* runs = (int16_t*)(alphas + (len + 1) * 2); - for (int i = 0; i < len; ++i) { + for (int i = 0; i < len; i++) { runs[i] = 1; alphas[i] = fullAlpha; } @@ -745,7 +655,7 @@ static void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, int y, } else { computeAlphaBelowLine(tempAlphas + uL - L, ul - (uL << 16), ll - (uL << 16), lDY, fullAlpha); - for (int i = uL; i < lL; ++i) { + for (int i = uL; i < lL; i++) { if (alphas[i - L] > tempAlphas[i - L]) { alphas[i - L] -= tempAlphas[i - L]; } else { @@ -766,7 +676,7 @@ static void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, int y, } else { computeAlphaAboveLine(tempAlphas + uR - L, ur - (uR << 16), lr - (uR << 16), rDY, fullAlpha); - for (int i = uR; i < lR; ++i) { + for (int i = uR; i < lR; i++) { if (alphas[i - L] > tempAlphas[i - L]) { alphas[i - L] -= tempAlphas[i - L]; } else { @@ -776,16 +686,11 @@ static void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, int y, } if (isUsingMask) { - for (int i = 0; i < len; ++i) { - if (needSafeCheck) { - safelyAddAlpha(&maskRow[L + i], alphas[i]); - } else { - addAlpha(&maskRow[L + i], alphas[i]); - } + for (int i=0; i<len; i++) { + addAlpha(maskRow[L + i], alphas[i]); } } else { - if (fullAlpha == 0xFF && !noRealBlitter) { - // Real blitter is faster than RunBasedAdditiveBlitter + if (fullAlpha == 0xFF) { // Real blitter is faster than RunBasedAdditiveBlitter blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs); } else { blitter->blitAntiH(L, y, alphas, len); @@ -797,11 +702,10 @@ static void blit_aaa_trapezoid_row(AdditiveBlitter* blitter, int y, } } -static SK_ALWAYS_INLINE void blit_trapezoid_row(AdditiveBlitter* blitter, int y, +static inline void blit_trapezoid_row(AdditiveBlitter* blitter, int y, SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, SkFixed lDY, SkFixed rDY, SkAlpha fullAlpha, - SkAlpha* maskRow, bool isUsingMask, bool noRealBlitter = false, - bool needSafeCheck = false) { + SkAlpha* maskRow, bool isUsingMask) { SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value if (ul > ur) { @@ -839,19 +743,16 @@ static SK_ALWAYS_INLINE void blit_trapezoid_row(AdditiveBlitter* blitter, int y, int len = SkFixedCeilToInt(joinLeft - ul); if (len == 1) { SkAlpha alpha = trapezoidToAlpha(joinLeft - ul, joinLeft - ll); - blit_single_alpha(blitter, y, ul >> 16, alpha, fullAlpha, maskRow, isUsingMask, - noRealBlitter, needSafeCheck); + blit_single_alpha(blitter, y, ul >> 16, alpha, fullAlpha, maskRow, isUsingMask); } else if (len == 2) { SkFixed first = joinLeft - SK_Fixed1 - ul; SkFixed second = ll - ul - first; SkAlpha a1 = partialTriangleToAlpha(first, lDY); SkAlpha a2 = fullAlpha - partialTriangleToAlpha(second, lDY); - blit_two_alphas(blitter, y, ul >> 16, a1, a2, fullAlpha, maskRow, isUsingMask, - noRealBlitter, needSafeCheck); + blit_two_alphas(blitter, y, ul >> 16, a1, a2, fullAlpha, maskRow, isUsingMask); } else { blit_aaa_trapezoid_row(blitter, y, ul, joinLeft, ll, joinLeft, lDY, SK_MaxS32, - fullAlpha, maskRow, isUsingMask, noRealBlitter, - needSafeCheck); + fullAlpha, maskRow, isUsingMask); } } // SkAAClip requires that we blit from left to right. @@ -859,30 +760,29 @@ static SK_ALWAYS_INLINE void blit_trapezoid_row(AdditiveBlitter* blitter, int y, if (joinLeft < joinRite) { blit_full_alpha(blitter, y, SkFixedFloorToInt(joinLeft), SkFixedFloorToInt(joinRite - joinLeft), - fullAlpha, maskRow, isUsingMask, noRealBlitter, needSafeCheck); + fullAlpha, maskRow, isUsingMask); } if (lr > joinRite) { int len = SkFixedCeilToInt(lr - joinRite); if (len == 1) { SkAlpha alpha = trapezoidToAlpha(ur - joinRite, lr - joinRite); blit_single_alpha(blitter, y, joinRite >> 16, alpha, fullAlpha, maskRow, - isUsingMask, noRealBlitter, needSafeCheck); + isUsingMask); } else if (len == 2) { SkFixed first = joinRite + SK_Fixed1 - ur; SkFixed second = lr - ur - first; SkAlpha a1 = fullAlpha - partialTriangleToAlpha(first, rDY); SkAlpha a2 = partialTriangleToAlpha(second, rDY); blit_two_alphas(blitter, y, joinRite >> 16, a1, a2, fullAlpha, maskRow, - isUsingMask, noRealBlitter, needSafeCheck); + isUsingMask); } else { blit_aaa_trapezoid_row(blitter, y, joinRite, ur, joinRite, lr, SK_MaxS32, rDY, - fullAlpha, maskRow, isUsingMask, noRealBlitter, - needSafeCheck); + fullAlpha, maskRow, isUsingMask); } } } else { blit_aaa_trapezoid_row(blitter, y, ul, ur, ll, lr, lDY, rDY, fullAlpha, maskRow, - isUsingMask, noRealBlitter, needSafeCheck); + isUsingMask); } } @@ -909,7 +809,7 @@ static SkAnalyticEdge* sort_edges(SkAnalyticEdge* list[], int count, SkAnalyticE SkTQSort(list, list + count - 1); // now make the edges linked in sorted order - for (int i = 1; i < count; ++i) { + for (int i = 1; i < count; i++) { list[i - 1]->fNext = list[i]; list[i]->fPrev = list[i - 1]; } @@ -999,9 +899,9 @@ static inline bool isSmoothEnough(SkAnalyticEdge* leftE, SkAnalyticEdge* riteE, return isSmoothEnough(leftE, currE, stop_y) && isSmoothEnough(riteE, nextCurrE, stop_y); } -static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, - AdditiveBlitter* blitter, int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, - bool isUsingMask) { +static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitter* blitter, + int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, + bool isUsingMask) { validate_sort((SkAnalyticEdge*)prevHead->fNext); SkAnalyticEdge* leftE = (SkAnalyticEdge*) prevHead->fNext; @@ -1230,408 +1130,14 @@ END_WALK: #endif } -/////////////////////////////////////////////////////////////////////////////// - -static inline void remove_edge(SkAnalyticEdge* edge) { - edge->fPrev->fNext = edge->fNext; - edge->fNext->fPrev = edge->fPrev; -} - -static inline void insert_edge_after(SkAnalyticEdge* edge, SkAnalyticEdge* afterMe) { - edge->fPrev = afterMe; - edge->fNext = afterMe->fNext; - afterMe->fNext->fPrev = edge; - afterMe->fNext = edge; -} - -static void backward_insert_edge_based_on_x(SkAnalyticEdge* edge) { - SkFixed x = edge->fX; - SkAnalyticEdge* prev = edge->fPrev; - while (prev->fPrev && prev->fX > x) { - prev = prev->fPrev; - } - if (prev->fNext != edge) { - remove_edge(edge); - insert_edge_after(edge, prev); - } -} - -static SkAnalyticEdge* backward_insert_start(SkAnalyticEdge* prev, SkFixed x) { - while (prev->fPrev && prev->fX > x) { - prev = prev->fPrev; - } - return prev; -} - -static inline void updateNextNextY(SkFixed y, SkFixed nextY, SkFixed* nextNextY) { - *nextNextY = y > nextY && y < *nextNextY ? y : *nextNextY; -} - -static inline void checkIntersection(const SkAnalyticEdge* edge, SkFixed nextY, SkFixed* nextNextY) -{ - if (edge->fPrev->fPrev && edge->fPrev->fX + edge->fPrev->fDX > edge->fX + edge->fDX) { - *nextNextY = nextY + (SK_Fixed1 >> SkAnalyticEdge::kDefaultAccuracy); - } -} - -static void insert_new_edges(SkAnalyticEdge* newEdge, SkFixed y, SkFixed* nextNextY) { - if (newEdge->fUpperY > y) { - updateNextNextY(newEdge->fUpperY, y, nextNextY); - return; - } - SkAnalyticEdge* prev = newEdge->fPrev; - if (prev->fX <= newEdge->fX) { - while (newEdge->fUpperY <= y) { - checkIntersection(newEdge, y, nextNextY); - updateNextNextY(newEdge->fLowerY, y, nextNextY); - newEdge = newEdge->fNext; - } - updateNextNextY(newEdge->fUpperY, y, nextNextY); - return; - } - // find first x pos to insert - SkAnalyticEdge* start = backward_insert_start(prev, newEdge->fX); - //insert the lot, fixing up the links as we go - do { - SkAnalyticEdge* next = newEdge->fNext; - do { - if (start->fNext == newEdge) { - goto nextEdge; - } - SkAnalyticEdge* after = start->fNext; - if (after->fX >= newEdge->fX) { - break; - } - SkASSERT(start != after); - start = after; - } while (true); - remove_edge(newEdge); - insert_edge_after(newEdge, start); -nextEdge: - checkIntersection(newEdge, y, nextNextY); - updateNextNextY(newEdge->fLowerY, y, nextNextY); - start = newEdge; - newEdge = next; - } while (newEdge->fUpperY <= y); - updateNextNextY(newEdge->fUpperY, y, nextNextY); -} - -static void validate_edges_for_y(const SkAnalyticEdge* edge, SkFixed y) { -#ifdef SK_DEBUG - while (edge->fUpperY <= y) { - SkASSERT(edge->fPrev && edge->fNext); - SkASSERT(edge->fPrev->fNext == edge); - SkASSERT(edge->fNext->fPrev == edge); - SkASSERT(edge->fUpperY <= edge->fLowerY); - SkASSERT(edge->fPrev->fPrev == nullptr || edge->fPrev->fX <= edge->fX); - edge = edge->fNext; - } -#endif -} - -// Return true if prev->fX, next->fX are too close in the current pixel row. -static inline bool edges_too_close(SkAnalyticEdge* prev, SkAnalyticEdge* next, SkFixed lowerY) { - // Note that even if the following test failed, the edges might still be very close to each - // other at some point within the current pixel row because of prev->fDX and next->fDX. - // However, to handle that case, we have to sacrafice more performance. - // I think the current quality is good enough (mainly by looking at Nebraska-StateSeal.svg) - // so I'll ignore fDX for performance tradeoff. - return next && prev && next->fUpperY < lowerY && prev->fX >= next->fX - SkAbs32(next->fDX); - // The following is more accurate but also slower. - // return (prev && prev->fPrev && next && next->fNext != nullptr && next->fUpperY < lowerY && - // prev->fX + SkAbs32(prev->fDX) >= next->fX - SkAbs32(next->fDX)); -} - -// This function exists for the case where the previous rite edge is removed because -// its fLowerY <= nextY -static inline bool edges_too_close(int prevRite, SkFixed ul, SkFixed ll) { - return prevRite > SkFixedFloorToInt(ul) || prevRite > SkFixedFloorToInt(ll); -} - -static inline void blit_saved_trapezoid(SkAnalyticEdge* leftE, SkFixed lowerY, - SkFixed lowerLeft, SkFixed lowerRite, - AdditiveBlitter* blitter, SkAlpha* maskRow, bool isUsingMask, bool noRealBlitter, - SkFixed leftClip, SkFixed rightClip) { - SkAnalyticEdge* riteE = leftE->fRiteE; - SkASSERT(riteE); - SkASSERT(riteE->fNext == nullptr || leftE->fSavedY == riteE->fSavedY); - SkASSERT(SkFixedFloorToInt(lowerY - 1) == SkFixedFloorToInt(leftE->fSavedY)); - int y = SkFixedFloorToInt(leftE->fSavedY); - // Instead of using f2a(lowerY - leftE->fSavedY), we use the following fullAlpha - // to elimiate cumulative error: if there are many fractional y scan lines within the - // same row, the former may accumulate the rounding error while the later won't. - SkAlpha fullAlpha = f2a(lowerY - SkIntToFixed(y)) - f2a(leftE->fSavedY - SkIntToFixed(y)); - // We need fSavedDY because the (quad or cubic) edge might be updated - blit_trapezoid_row(blitter, y, - SkTMax(leftE->fSavedX, leftClip), SkTMin(riteE->fSavedX, rightClip), - SkTMax(lowerLeft, leftClip), SkTMin(lowerRite, rightClip), - leftE->fSavedDY, riteE->fSavedDY, fullAlpha, maskRow, isUsingMask, - noRealBlitter || - (fullAlpha == 0xFF && (edges_too_close(leftE->fPrev, leftE, lowerY) - || edges_too_close(riteE, riteE->fNext, lowerY))), - true); - leftE->fRiteE = nullptr; -} - -static inline void deferred_blit(SkAnalyticEdge* leftE, SkAnalyticEdge* riteE, - SkFixed left, SkFixed leftDY, // don't save leftE->fX/fDY as they may have been updated - SkFixed y, SkFixed nextY, bool isIntegralNextY, bool leftEnds, bool riteEnds, - AdditiveBlitter* blitter, SkAlpha* maskRow, bool isUsingMask, bool noRealBlitter, - SkFixed leftClip, SkFixed rightClip, int yShift) { - if (leftE->fRiteE && leftE->fRiteE != riteE) { - // leftE's right edge changed. Blit the saved trapezoid. - SkASSERT(leftE->fRiteE->fNext == nullptr || leftE->fRiteE->fY == y); - blit_saved_trapezoid(leftE, y, left, leftE->fRiteE->fX, - blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); - } - if (!leftE->fRiteE) { - // Save and defer blitting the trapezoid - SkASSERT(riteE->fRiteE == nullptr); - SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY); - SkASSERT(riteE->fNext == nullptr || riteE->fY == y); - leftE->saveXY(left, y, leftDY); - riteE->saveXY(riteE->fX, y, riteE->fDY); - leftE->fRiteE = riteE; - } - SkASSERT(leftE->fPrev == nullptr || leftE->fY == nextY); - riteE->goY(nextY, yShift); - // Always blit when edges end or nextY is integral - if (isIntegralNextY || leftEnds || riteEnds) { - blit_saved_trapezoid(leftE, nextY, leftE->fX, riteE->fX, - blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); - } -} - -static void aaa_walk_edges(SkAnalyticEdge* prevHead, SkAnalyticEdge* nextTail, - SkPath::FillType fillType, AdditiveBlitter* blitter, int start_y, int stop_y, - SkFixed leftClip, SkFixed rightClip, bool isUsingMask, bool forceRLE, bool useDeferred, - bool skipIntersect) { - prevHead->fX = prevHead->fUpperX = leftClip; - nextTail->fX = nextTail->fUpperX = rightClip; - SkFixed y = SkTMax(prevHead->fNext->fUpperY, SkIntToFixed(start_y)); - SkFixed nextNextY = SK_MaxS32; - - { - SkAnalyticEdge* edge; - for(edge = prevHead->fNext; edge->fUpperY <= y; edge = edge->fNext) { - edge->goY(y); - updateNextNextY(edge->fLowerY, y, &nextNextY); - } - updateNextNextY(edge->fUpperY, y, &nextNextY); - } - - // returns 1 for evenodd, -1 for winding, regardless of inverse-ness - int windingMask = (fillType & 1) ? 1 : -1; - - bool isInverse = SkPath::IsInverseFillType(fillType); - - if (isInverse && SkIntToFixed(start_y) != y) { - int width = SkFixedFloorToInt(rightClip - leftClip); - if (SkFixedFloorToInt(y) != start_y) { - blitter->getRealBlitter()->blitRect(SkFixedFloorToInt(leftClip), start_y, - width, SkFixedFloorToInt(y) - start_y); - start_y = SkFixedFloorToInt(y); - } - SkAlpha* maskRow = isUsingMask ? static_cast<MaskAdditiveBlitter*>(blitter)->getRow(start_y) - : nullptr; - blit_full_alpha(blitter, start_y, SkFixedFloorToInt(leftClip), width, - f2a(y - SkIntToFixed(start_y)), maskRow, isUsingMask, false, false); - } - - while (true) { - int w = 0; - bool in_interval = isInverse; - SkFixed prevX = prevHead->fX; - SkFixed nextY = SkTMin(nextNextY, SkFixedCeilToFixed(y + 1)); - bool isIntegralNextY = (nextY & (SK_Fixed1 - 1)) == 0; - SkAnalyticEdge* currE = prevHead->fNext; - SkAnalyticEdge* leftE = prevHead; - SkFixed left = leftClip; - SkFixed leftDY = 0; - bool leftEnds = false; - int prevRite = SkFixedFloorToInt(leftClip); - - nextNextY = SK_MaxS32; - - SkASSERT((nextY & ((SK_Fixed1 >> 2) - 1)) == 0); - int yShift = 0; - if ((nextY - y) & (SK_Fixed1 >> 2)) { - yShift = 2; - nextY = y + (SK_Fixed1 >> 2); - } else if ((nextY - y) & (SK_Fixed1 >> 1)) { - yShift = 1; - SkASSERT(nextY == y + (SK_Fixed1 >> 1)); - } - - SkAlpha fullAlpha = f2a(nextY - y); - - // If we're using mask blitter, we advance the mask row in this function - // to save some "if" condition checks. - SkAlpha* maskRow = nullptr; - if (isUsingMask) { - maskRow = static_cast<MaskAdditiveBlitter*>(blitter)->getRow(SkFixedFloorToInt(y)); - } - - SkASSERT(currE->fPrev == prevHead); - validate_edges_for_y(currE, y); - - // Even if next - y == SK_Fixed1, we can still break the left-to-right order requirement - // of the SKAAClip: |\| (two trapezoids with overlapping middle wedges) - bool noRealBlitter = forceRLE; // forceRLE && (nextY - y != SK_Fixed1); - - while (currE->fUpperY <= y) { - SkASSERT(currE->fLowerY >= nextY); - SkASSERT(currE->fY == y); - - w += currE->fWinding; - bool prev_in_interval = in_interval; - in_interval = !(w & windingMask) == isInverse; - - bool isLeft = in_interval && !prev_in_interval; - bool isRite = !in_interval && prev_in_interval; - bool currEnds = currE->fLowerY == nextY; - - if (useDeferred) { - if (currE->fRiteE && !isLeft) { - // currE is a left edge previously, but now it's not. - // Blit the trapezoid between fSavedY and y. - SkASSERT(currE->fRiteE->fY == y); - blit_saved_trapezoid(currE, y, currE->fX, currE->fRiteE->fX, - blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); - } - if (leftE->fRiteE == currE && !isRite) { - // currE is a right edge previously, but now it's not. - // Moreover, its corresponding leftE doesn't change (otherwise we'll handle it - // in the previous if clause). Hence we blit the trapezoid. - blit_saved_trapezoid(leftE, y, left, currE->fX, - blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); - } - } - - if (isRite) { - if (useDeferred) { - deferred_blit(leftE, currE, left, leftDY, y, nextY, isIntegralNextY, - leftEnds, currEnds, blitter, maskRow, isUsingMask, noRealBlitter, - leftClip, rightClip, yShift); - } else { - SkFixed rite = currE->fX; - currE->goY(nextY, yShift); - if (leftE->fDX < 0) { - left = SkTMax(leftClip, left); - leftE->fX = SkTMax(leftClip, leftE->fX); - } else { - left = SkTMin(rightClip, left); - leftE->fX = SkTMin(rightClip, leftE->fX); - } - if (currE->fDX < 0) { - rite = SkTMax(leftClip, rite); - currE->fX = SkTMax(leftClip, currE->fX); - } else { - rite = SkTMin(rightClip, rite); - currE->fX = SkTMin(rightClip, currE->fX); - } - blit_trapezoid_row(blitter, y >> 16, left, rite, leftE->fX, currE->fX, - leftDY, currE->fDY, fullAlpha, maskRow, isUsingMask, - noRealBlitter || (fullAlpha == 0xFF && ( - edges_too_close(prevRite, left, leftE->fX) || - edges_too_close(currE, currE->fNext, nextY) - )), - true); - prevRite = SkFixedCeilToInt(SkTMax(rite, currE->fX)); - } - } else { - if (isLeft) { - left = currE->fX; - leftDY = currE->fDY; - leftE = currE; - leftEnds = leftE->fLowerY == nextY; - } - currE->goY(nextY, yShift); - } - - - SkAnalyticEdge* next = currE->fNext; - SkFixed newX; - - while (currE->fLowerY <= nextY) { - if (currE->fCurveCount < 0) { - SkAnalyticCubicEdge* cubicEdge = (SkAnalyticCubicEdge*)currE; - cubicEdge->keepContinuous(); - if (!cubicEdge->updateCubic()) { - break; - } - } else if (currE->fCurveCount > 0) { - SkAnalyticQuadraticEdge* quadEdge = (SkAnalyticQuadraticEdge*)currE; - quadEdge->keepContinuous(); - if (!quadEdge->updateQuadratic()) { - break; - } - } else { - break; - } - } - SkASSERT(currE->fY == nextY); - - if (currE->fLowerY <= nextY) { - remove_edge(currE); - } else { - updateNextNextY(currE->fLowerY, nextY, &nextNextY); - newX = currE->fX; - SkASSERT(currE->fLowerY > nextY); - if (newX < prevX) { // ripple currE backwards until it is x-sorted - // If the crossing edge is a right edge, blit the saved trapezoid. - if (leftE->fRiteE == currE && useDeferred) { - SkASSERT(leftE->fY == nextY && currE->fY == nextY); - blit_saved_trapezoid(leftE, nextY, leftE->fX, currE->fX, - blitter, maskRow, isUsingMask, noRealBlitter, leftClip, rightClip); - } - backward_insert_edge_based_on_x(currE); - } else { - prevX = newX; - } - if (!skipIntersect) { - checkIntersection(currE, nextY, &nextNextY); - } - } - - currE = next; - SkASSERT(currE); - } - - // was our right-edge culled away? - if (in_interval) { - if (useDeferred) { - deferred_blit(leftE, nextTail, left, leftDY, y, nextY, isIntegralNextY, - leftEnds, false, blitter, maskRow, isUsingMask, noRealBlitter, - leftClip, rightClip, yShift); - } else { - blit_trapezoid_row(blitter, y >> 16, left, rightClip, leftE->fX, rightClip, - leftDY, 0, fullAlpha, maskRow, isUsingMask, - noRealBlitter || - (fullAlpha == 0xFF && edges_too_close(leftE->fPrev, leftE, nextY)), - true); - } - } - - if (forceRLE) { - ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, nextY); - } - - y = nextY; - if (y >= SkIntToFixed(stop_y)) { - break; - } - - // now currE points to the first edge with a fUpperY larger than the previous y - insert_new_edges(currE, y, &nextNextY); - } -} - -static void aaa_fill_path(const SkPath& path, const SkIRect& clipRect, - AdditiveBlitter* blitter, int start_y, int stop_y, bool pathContainedInClip, - bool isUsingMask, bool forceRLE) { // forceRLE implies that SkAAClip is calling us +void aaa_fill_path(const SkPath& path, const SkIRect& clipRect, AdditiveBlitter* blitter, + int start_y, int stop_y, bool pathContainedInClip, bool isUsingMask, + bool forceRLE) { // forceRLE implies that SkAAClip is calling us SkASSERT(blitter); + // we only implemented the convex shapes yet + SkASSERT(!path.isInverseFillType() && path.isConvex()); + SkEdgeBuilder builder; // If we're convex, then we need both edges, even the right edge is past the clip @@ -1660,8 +1166,7 @@ static void aaa_fill_path(const SkPath& path, const SkIRect& clipRect, rect.fBottom = stop_y; } if (!rect.isEmpty()) { - blitter->getRealBlitter()->blitRect(rect.fLeft, rect.fTop, - rect.width(), rect.height()); + blitter->blitRect(rect.fLeft, rect.fTop, rect.width(), rect.height()); } } return; @@ -1671,7 +1176,6 @@ static void aaa_fill_path(const SkPath& path, const SkIRect& clipRect, // this returns the first and last edge after they're sorted into a dlink list SkAnalyticEdge* edge = sort_edges(list, count, &last); - headEdge.fRiteE = nullptr; headEdge.fPrev = nullptr; headEdge.fNext = edge; headEdge.fUpperY = headEdge.fLowerY = SK_MinS32; @@ -1681,14 +1185,13 @@ static void aaa_fill_path(const SkPath& path, const SkIRect& clipRect, headEdge.fUpperX = SK_MinS32; edge->fPrev = &headEdge; - tailEdge.fRiteE = nullptr; tailEdge.fPrev = last; tailEdge.fNext = nullptr; tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32; - tailEdge.fX = SK_MaxS32; - tailEdge.fDX = 0; - tailEdge.fDY = SK_MaxS32; - tailEdge.fUpperX = SK_MaxS32; + headEdge.fX = SK_MaxS32; + headEdge.fDX = 0; + headEdge.fDY = SK_MaxS32; + headEdge.fUpperX = SK_MaxS32; last->fNext = &tailEdge; // now edge is the head of the sorted linklist @@ -1700,32 +1203,22 @@ static void aaa_fill_path(const SkPath& path, const SkIRect& clipRect, stop_y = clipRect.fBottom; } - SkFixed leftBound = SkIntToFixed(rect.fLeft); - SkFixed rightBound = SkIntToFixed(rect.fRight); - if (isUsingMask) { - // If we're using mask, then we have to limit the bound within the path bounds. - // Otherwise, the edge drift may access an invalid address inside the mask. - SkIRect ir; - path.getBounds().roundOut(&ir); - leftBound = SkTMax(leftBound, SkIntToFixed(ir.fLeft)); - rightBound = SkTMin(rightBound, SkIntToFixed(ir.fRight)); - } - if (!path.isInverseFillType() && path.isConvex()) { SkASSERT(count >= 2); // convex walker does not handle missing right edges + SkFixed leftBound = SkIntToFixed(rect.fLeft); + SkFixed rightBound = SkIntToFixed(rect.fRight); + if (isUsingMask) { + // If we're using mask, then we have to limit the bound within the path bounds. + // Otherwise, the edge drift may access an invalid address inside the mask. + SkIRect ir; + path.getBounds().roundOut(&ir); + leftBound = SkTMax(leftBound, SkIntToFixed(ir.fLeft)); + rightBound = SkTMin(rightBound, SkIntToFixed(ir.fRight)); + } aaa_walk_convex_edges(&headEdge, blitter, start_y, stop_y, leftBound, rightBound, isUsingMask); } else { - // Only use deferred blitting if there are many edges. - bool useDeferred = count > - (SkFixedFloorToInt(tailEdge.fPrev->fLowerY - headEdge.fNext->fUpperY) + 1) * 4; - - // We skip intersection computation if there are many points which probably already - // give us enough fractional scan lines. - bool skipIntersect = path.countPoints() > (stop_y - start_y) / 2; - - aaa_walk_edges(&headEdge, &tailEdge, path.getFillType(), blitter, start_y, stop_y, - leftBound, rightBound, isUsingMask, forceRLE, useDeferred, skipIntersect); + SkFAIL("Concave AAA is not yet implemented!"); } } @@ -1775,13 +1268,11 @@ void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter if (origClip.isEmpty()) { return; } - #ifdef SK_SUPPORT_LEGACY_AAA if (path.isInverseFillType() || !path.isConvex()) { // Fall back as we only implemented the algorithm for convex shapes yet. SkScan::AntiFillPath(path, origClip, blitter, forceRLE); return; } - #endif const bool isInverse = path.isInverseFillType(); SkIRect ir; @@ -1846,7 +1337,9 @@ void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter blitter = clipper.getBlitter(); if (isInverse) { - sk_blit_above(blitter, ir, *clipRgn); + // Currently, we use the old path to render the inverse path, + // so we don't need this. + // sk_blit_above(blitter, ir, *clipRgn); } SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); @@ -1855,18 +1348,16 @@ void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter MaskAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, clipRect == nullptr, true, forceRLE); - } else if (!isInverse && path.isConvex()) { - RunBasedAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); - aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, - clipRect == nullptr, false, forceRLE); } else { - SafeRLEAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); + RunBasedAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, clipRect == nullptr, false, forceRLE); } if (isInverse) { - sk_blit_below(blitter, ir, *clipRgn); + // Currently, we use the old path to render the inverse path, + // so we don't need this. + // sk_blit_below(blitter, ir, *clipRgn); } } diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp index 16c91a9c1c..1d214e3078 100644 --- a/src/core/SkScan_AntiPath.cpp +++ b/src/core/SkScan_AntiPath.cpp @@ -753,27 +753,9 @@ void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip, } } -static bool suitableForAAA(const SkPath& path) { -#ifdef SK_SUPPORT_LEGACY_AAA - return true; -#endif - if (gSkForceAnalyticAA.load()) { - return true; - } - const SkRect& bounds = path.getBounds(); - // When the path have so many points compared to the size of its bounds/resolution, - // it indicates that the path is not quite smooth in the current resolution: - // the expected number of turning points in every pixel row/column is significantly greater than - // zero. Hence Aanlytic AA is not likely to produce visible quality improvents, and Analytic AA - // might be slower than supersampling. - return path.countPoints() < SkTMax(bounds.width(), bounds.height()) / 2 - 10; -} - void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) { - // Do not use AAA if path is too complicated: - // there won't be any speedup or significant visual improvement. - if (gSkUseAnalyticAA.load() && suitableForAAA(path)) { + if (gSkUseAnalyticAA.load()) { SkScan::AAAFillPath(path, clip, blitter); return; } diff --git a/tools/flags/SkCommonFlags.cpp b/tools/flags/SkCommonFlags.cpp index 0148bcd820..52a5388ddf 100644 --- a/tools/flags/SkCommonFlags.cpp +++ b/tools/flags/SkCommonFlags.cpp @@ -68,10 +68,6 @@ DEFINE_bool2(pre_log, p, false, "Log before running each test. May be incomprehe DEFINE_bool(analyticAA, true, "If false, disable analytic anti-aliasing"); -DEFINE_bool(forceAnalyticAA, false, "Force analytic anti-aliasing even if the path is complicated: " - "whether it's concave or convex, we consider a path complicated" - "if its number of points is comparable to its resolution."); - bool CollectImages(SkCommandLineFlags::StringArray images, SkTArray<SkString>* output) { SkASSERT(output); diff --git a/tools/flags/SkCommonFlags.h b/tools/flags/SkCommonFlags.h index 92ac141dad..1a707c8586 100644 --- a/tools/flags/SkCommonFlags.h +++ b/tools/flags/SkCommonFlags.h @@ -33,7 +33,6 @@ DECLARE_bool(veryVerbose); DECLARE_string(writePath); DECLARE_bool(pre_log); DECLARE_bool(analyticAA); -DECLARE_bool(forceAnalyticAA); DECLARE_string(key); DECLARE_string(properties); |