diff options
author | 2017-09-25 11:18:08 -0400 | |
---|---|---|
committer | 2017-09-25 18:56:10 +0000 | |
commit | f60c1a3ef905dc034dfcc91267fea382f77acea6 (patch) | |
tree | 1d70ea45a01b917ab4e091102656efcf7dfc8f11 /src | |
parent | 29bf84f08a3716ae672dc06c237fc259fccbd136 (diff) |
Reland blitFatAntiRect with guard to avoid overhead in MaskAdditiveBlitter
This results in ~15% (~700ns vs ~600ns) speedup for
path_fill_small_rect bench in 8888 config. Some skps have a lot of stroked
horizontal/vertical lines (e.g., bar charts) so this improvement could
have a great impact there. For example, cereal converts Microsoft word docx
to PNGs on server and the sample docx has a big bar chart. That inspired
this improvement.
Bug: skia:
Change-Id: If191b8beca58c5c08b356b64ffef93d51761fd0a
Reviewed-on: https://skia-review.googlesource.com/50043
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Yuqian Li <liyuqian@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkScanPriv.h | 17 | ||||
-rw-r--r-- | src/core/SkScan_AAAPath.cpp | 20 | ||||
-rw-r--r-- | src/core/SkScan_DAAPath.cpp | 11 |
3 files changed, 37 insertions, 11 deletions
diff --git a/src/core/SkScanPriv.h b/src/core/SkScanPriv.h index f8d3bb23be..8883be0537 100644 --- a/src/core/SkScanPriv.h +++ b/src/core/SkScanPriv.h @@ -117,6 +117,23 @@ static bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) { return false; } +// Check if the path is a rect and fat enough after clipping; if so, blit it. +static inline bool TryBlitFatAntiRect(SkBlitter* blitter, const SkPath& path, const SkIRect& clip) { + SkRect rect; + if (!path.isRect(&rect)) { + return false; // not rect + } + if (!rect.intersect(SkRect::Make(clip))) { + return true; // The intersection is empty. Hence consider it done. + } + SkIRect bounds = rect.roundOut(); + if (bounds.width() < 3 || bounds.height() < 3) { + return false; // not fat + } + blitter->blitFatAntiRect(rect); + return true; +} + using FillPathFunc = std::function<void(const SkPath& path, SkBlitter* blitter, bool isInverse, const SkIRect& ir, const SkRegion* clipRgn, const SkIRect* clipRect, bool forceRLE)>; diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp index e5478eaf69..b6377edbce 100644 --- a/src/core/SkScan_AAAPath.cpp +++ b/src/core/SkScan_AAAPath.cpp @@ -1676,29 +1676,43 @@ void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter bool forceRLE) { FillPathFunc fillPathFunc = [](const SkPath& path, SkBlitter* blitter, bool isInverse, const SkIRect& ir, const SkRegion* clipRgn, const SkIRect* clipRect, bool forceRLE){ + const SkIRect& clipBounds = clipRgn->getBounds(); + // The mask blitter (where we store intermediate alpha values directly in a mask, and then // call the real blitter once in the end to blit the whole mask) is faster than the RLE // blitter when the blit region is small enough (i.e., canHandleRect(ir)). // When isInverse is true, the blit region is no longer ir so we won't use the mask blitter. // The caller may also use the forceRLE flag to force not using the mask blitter. + // Also, when the path is a simple rect, preparing a mask and blitting it might have too + // much overhead. Hence we'll use blitFatAntiRect to avoid the mask and its overhead. if (MaskAdditiveBlitter::canHandleRect(ir) && !isInverse && !forceRLE) { +#ifdef SK_SUPPORT_LEGACY_SMALLRECT_AA MaskAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); - aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, + aaa_fill_path(path, clipBounds, &additiveBlitter, ir.fTop, ir.fBottom, clipRect == nullptr, true, forceRLE); +#else + // blitFatAntiRect is slower than the normal AAA flow without MaskAdditiveBlitter. + // Hence only tryBlitFatAntiRect when MaskAdditiveBlitter would have been used. + if (!TryBlitFatAntiRect(blitter, path, clipBounds)) { + MaskAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); + aaa_fill_path(path, clipBounds, &additiveBlitter, ir.fTop, ir.fBottom, + clipRect == nullptr, true, forceRLE); + } +#endif } else if (!isInverse && path.isConvex()) { // If the filling area is convex (i.e., path.isConvex && !isInverse), our simpler // aaa_walk_convex_edges won't generate alphas above 255. Hence we don't need // SafeRLEAdditiveBlitter (which is slow due to clamping). The basic RLE blitter // RunBasedAdditiveBlitter would suffice. RunBasedAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); - aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, + aaa_fill_path(path, clipBounds, &additiveBlitter, ir.fTop, ir.fBottom, clipRect == nullptr, false, forceRLE); } else { // If the filling area might not be convex, the more involved aaa_walk_edges would // be called and we have to clamp the alpha downto 255. The SafeRLEAdditiveBlitter // does that at a cost of performance. SafeRLEAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); - aaa_fill_path(path, clipRgn->getBounds(), &additiveBlitter, ir.fTop, ir.fBottom, + aaa_fill_path(path, clipBounds, &additiveBlitter, ir.fTop, ir.fBottom, clipRect == nullptr, false, forceRLE); } }; diff --git a/src/core/SkScan_DAAPath.cpp b/src/core/SkScan_DAAPath.cpp index 9250d02f07..a9195eb085 100644 --- a/src/core/SkScan_DAAPath.cpp +++ b/src/core/SkScan_DAAPath.cpp @@ -328,14 +328,9 @@ void SkScan::DAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter SkIRect clippedIR = ir; clippedIR.intersect(clipBounds); - SkRect rect; - if (!isInverse && path.isRect(&rect) && clippedIR.height() >= 3 && clippedIR.width() >= 3) { - // The overhead of even constructing SkCoverageDeltaList/Mask is too big. So just blit. - bool nonEmpty = rect.intersect(SkRect::Make(clipBounds)); - SkASSERT(nonEmpty); // do_fill_path should have already handled the empty case - if (nonEmpty) { - blitter->blitFatAntiRect(rect); - } + // The overhead of even constructing SkCoverageDeltaList/Mask is too big. + // So TryBlitFatAntiRect and return if it's successful. + if (TryBlitFatAntiRect(blitter, path, clipBounds)) { return; } |