diff options
author | tomhudson@chromium.org <tomhudson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-20 23:21:14 +0000 |
---|---|---|
committer | tomhudson@chromium.org <tomhudson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-20 23:21:14 +0000 |
commit | 7d93ac3af111001887e56b4ddc682d4649423cee (patch) | |
tree | af6213f910fddd02899020716ec38eb1fb90538c /skia | |
parent | 43672bd596c719c963579e159dea08e6545d026f (diff) | |
download | chromium_src-7d93ac3af111001887e56b4ddc682d4649423cee.zip chromium_src-7d93ac3af111001887e56b4ddc682d4649423cee.tar.gz chromium_src-7d93ac3af111001887e56b4ddc682d4649423cee.tar.bz2 |
Improve detection of cheap-to-rasterize SkPictures.
Assumes most operations are very expensive; estimates cost of some
simple operations (drawing rectangles and text) so that we can identify
*some* cheap SkPictures.
We can't currently predict the cost of any draw requiring a bitmap,
because it could have a lazy decode pending or have been decoded but
then evicted from cache. Until we have a better handle on things,
assume all bitmaps are at least moderately expensive.
Has a BadlyWrong error rate on top_25.json of well under 1%,
even retaining the 1ms threshold for BadlyWrong (when 2-3ms is more
reasonable) and even leaving the compositor render worker active
(which can cause cheap tasks to be swapped out and thus falsely
declared BadlyWrong).
Has a SafelyWrong error rate of around 15-20%; this is space for
improvement.
BUG=173426,222031
R=skyostil,junov
Review URL: https://chromiumcodereview.appspot.com/12620013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@189455 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia')
-rw-r--r-- | skia/ext/analysis_canvas.cc | 129 | ||||
-rw-r--r-- | skia/ext/analysis_canvas_unittest.cc | 13 |
2 files changed, 101 insertions, 41 deletions
diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc index 6a07d40..93580b0 100644 --- a/skia/ext/analysis_canvas.cc +++ b/skia/ext/analysis_canvas.cc @@ -13,16 +13,24 @@ namespace { -// FIXME: Arbitrary number. Requires tuning & experimentation. +// FIXME: Arbitrary numbers. Requires tuning & experimentation. // Probably requires per-platform tuning; N10 average draw call takes // 25x as long as Z620. const int gPictureCostThreshold = 1000; +const int kUnknownExpensiveCost = 500; +const int kUnknownBitmapCost = 1000; // URI label for a lazily decoded SkPixelRef. const char kLabelLazyDecoded[] = "lazy"; const int kLabelLazyDecodedLength = 4; -static bool isSolidColorPaint(const SkPaint& paint) { +// Estimate of rasterization performance on mid-low-range hardware, +// drawing rectangles with simple paints. +const int kSimpleRectPixelsPerUS = 1000; +const int kComplexRectPixelsPerUS = 100; +const int kSimpleTextCharPerUS = 2; + +bool isSolidColorPaint(const SkPaint& paint) { SkXfermode::Mode xferMode; // getXfermode can return a NULL, but that is handled @@ -43,9 +51,9 @@ static bool isSolidColorPaint(const SkPaint& paint) { xferMode == SkXfermode::kSrcOver_Mode)); } -static bool isFullQuad(const SkDraw& draw, - const SkRect& canvasRect, - const SkRect& drawnRect) { +bool isFullQuad(const SkDraw& draw, + const SkRect& canvasRect, + const SkRect& drawnRect) { // If the transform results in a non-axis aligned // rect, then be conservative and return false. @@ -72,6 +80,12 @@ static bool isFullQuad(const SkDraw& draw, drawBitmapRect.contains(canvasRect); } +bool hasBitmap(const SkPaint& paint) { + SkShader* shader = paint.getShader(); + return shader && + (SkShader::kNone_BitmapType != shader->asABitmap(NULL, NULL, NULL)); +} + } // namespace namespace skia { @@ -163,7 +177,8 @@ void AnalysisDevice::consumeLazyPixelRefs(LazyPixelRefList* pixelRefs) { } void AnalysisDevice::clear(SkColor color) { - ++estimatedCost_; + // FIXME: cost here should be simple rect of device size + estimatedCost_ += kUnknownExpensiveCost; isTransparent_ = (!isForcedNotTransparent_ && SkColorGetA(color) == 0); @@ -177,30 +192,40 @@ void AnalysisDevice::clear(SkColor color) { } void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { - ++estimatedCost_; + estimatedCost_ += kUnknownExpensiveCost; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint& paint) { - ++estimatedCost_; + estimatedCost_ += kUnknownExpensiveCost; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint& paint) { // FIXME: if there's a pending image decode & resize, more expensive + estimatedCost_ += 1 + rect.width() * rect.height() / kSimpleRectPixelsPerUS; if (paint.getMaskFilter()) { - estimatedCost_ += 300; + estimatedCost_ += kUnknownExpensiveCost; } - ++estimatedCost_; - addBitmapFromPaint(paint); + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } + bool doesCoverCanvas = isFullQuad(draw, SkRect::MakeWH(width(), height()), rect); @@ -245,15 +270,18 @@ void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) { - ++estimatedCost_; + estimatedCost_ += kUnknownExpensiveCost; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, const SkPaint& paint, - const SkMatrix* prePathMatrix , + const SkMatrix* prePathMatrix, bool pathIsMutable ) { // On Z620, every antialiased path costs us about 300us. // We've only seen this in practice on filled paths, but @@ -261,16 +289,23 @@ void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, if (paint.getMaskFilter()) { estimatedCost_ += 300; } - ++estimatedCost_; + // FIXME: horrible overestimate if the path is stroked instead of filled + estimatedCost_ += 1 + path.getBounds().width() * + path.getBounds().height() / kSimpleRectPixelsPerUS; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, const SkIRect* srcRectOrNull, const SkMatrix& matrix, const SkPaint& paint) { - ++estimatedCost_; + estimatedCost_ += kUnknownExpensiveCost; + //DCHECK(hasBitmap(paint)); + estimatedCost_ += kUnknownBitmapCost; isSolidColor_ = false; isTransparent_ = false; addBitmap(bitmap); @@ -278,7 +313,9 @@ void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { - ++estimatedCost_; + estimatedCost_ += kUnknownExpensiveCost; + //DCHECK(hasBitmap(paint)); + estimatedCost_ += kUnknownBitmapCost; isSolidColor_ = false; isTransparent_ = false; addBitmap(bitmap); @@ -287,7 +324,10 @@ void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, void AnalysisDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint) { - ++estimatedCost_; + // FIXME: we also accumulate cost from drawRect() + estimatedCost_ += 1 + dst.width() * dst.height() / kComplexRectPixelsPerUS; + //DCHECK(hasBitmap(paint)); + estimatedCost_ += kUnknownBitmapCost; // Call drawRect to determine transparency, // but reset solid color to false. @@ -299,30 +339,41 @@ void AnalysisDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, SkScalar x, SkScalar y, const SkPaint& paint) { - ++estimatedCost_; + estimatedCost_ += 1 + len / kSimpleTextCharPerUS; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } -void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, +void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, + size_t len, const SkScalar pos[], SkScalar constY, int scalarsPerPos, const SkPaint& paint) { // FIXME: On Z620, every glyph cache miss costs us about 10us. // We don't have a good mechanism for predicting glyph cache misses. - ++estimatedCost_; + estimatedCost_ += 1 + len / kSimpleTextCharPerUS; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } -void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, +void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, + size_t len, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { - ++estimatedCost_; + estimatedCost_ += 1 + len / kSimpleTextCharPerUS; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } #ifdef SK_BUILD_FOR_ANDROID @@ -330,10 +381,13 @@ void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len, const SkPoint pos[], const SkPaint& paint, const SkPath& path, const SkMatrix* matrix) { - ++estimatedCost_; + estimatedCost_ += 1 + len / kSimpleTextCharPerUS; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } #endif @@ -343,15 +397,20 @@ void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, const SkColor colors[], SkXfermode* xmode, const uint16_t indices[], int indexCount, const SkPaint& paint) { - ++estimatedCost_; + estimatedCost_ += kUnknownExpensiveCost; + if (hasBitmap(paint)) { + estimatedCost_ += kUnknownBitmapCost; + addBitmapFromPaint(paint); + } isSolidColor_ = false; isTransparent_ = false; - addBitmapFromPaint(paint); } void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, - const SkPaint&) { - ++estimatedCost_; + const SkPaint& paint) { + estimatedCost_ += kUnknownExpensiveCost; + if (hasBitmap(paint)) + estimatedCost_ += kUnknownBitmapCost; isSolidColor_ = false; isTransparent_ = false; } diff --git a/skia/ext/analysis_canvas_unittest.cc b/skia/ext/analysis_canvas_unittest.cc index 1623732..f403a59 100644 --- a/skia/ext/analysis_canvas_unittest.cc +++ b/skia/ext/analysis_canvas_unittest.cc @@ -46,7 +46,8 @@ class TestShader : public SkShader { SkShader::BitmapType asABitmap(SkBitmap* bitmap, SkMatrix*, TileMode xy[2]) const { - *bitmap = *bitmap_; + if (bitmap) + *bitmap = *bitmap_; return SkShader::kDefault_BitmapType; } @@ -92,7 +93,7 @@ TEST(AnalysisCanvasTest, ClearCanvas) { EXPECT_TRUE(canvas.getColorIfSolid(&outputColor)); EXPECT_FALSE(canvas.isTransparent()); - EXPECT_TRUE(canvas.isCheap()); + EXPECT_FALSE(canvas.isCheap()); EXPECT_EQ(outputColor, color); // Translucent color @@ -101,7 +102,7 @@ TEST(AnalysisCanvasTest, ClearCanvas) { EXPECT_FALSE(canvas.getColorIfSolid(&outputColor)); EXPECT_FALSE(canvas.isTransparent()); - EXPECT_TRUE(canvas.isCheap()); + EXPECT_FALSE(canvas.isCheap()); // Test helper methods solidColorFill(canvas); @@ -145,7 +146,7 @@ TEST(AnalysisCanvasTest, ComplexActions) { EXPECT_FALSE(canvas.getColorIfSolid(&outputColor)); EXPECT_FALSE(canvas.isTransparent()); - EXPECT_TRUE(canvas.isCheap()); + EXPECT_FALSE(canvas.isCheap()); // Draw oval test. solidColorFill(canvas); @@ -153,7 +154,7 @@ TEST(AnalysisCanvasTest, ComplexActions) { EXPECT_FALSE(canvas.getColorIfSolid(&outputColor)); EXPECT_FALSE(canvas.isTransparent()); - EXPECT_TRUE(canvas.isCheap()); + EXPECT_FALSE(canvas.isCheap()); // Draw bitmap test. solidColorFill(canvas); @@ -163,7 +164,7 @@ TEST(AnalysisCanvasTest, ComplexActions) { EXPECT_FALSE(canvas.getColorIfSolid(&outputColor)); EXPECT_FALSE(canvas.isTransparent()); - EXPECT_TRUE(canvas.isCheap()); + EXPECT_FALSE(canvas.isCheap()); } TEST(AnalysisCanvasTest, SimpleDrawRect) { |