summaryrefslogtreecommitdiffstats
path: root/skia
diff options
context:
space:
mode:
authortomhudson@chromium.org <tomhudson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-20 23:21:14 +0000
committertomhudson@chromium.org <tomhudson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-20 23:21:14 +0000
commit7d93ac3af111001887e56b4ddc682d4649423cee (patch)
treeaf6213f910fddd02899020716ec38eb1fb90538c /skia
parent43672bd596c719c963579e159dea08e6545d026f (diff)
downloadchromium_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.cc129
-rw-r--r--skia/ext/analysis_canvas_unittest.cc13
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) {