diff --git a/cc/picture.cc b/cc/picture.cc index c8fcd450428373..23793cf8f163f3 100644 --- a/cc/picture.cc +++ b/cc/picture.cc @@ -6,6 +6,7 @@ #include "cc/content_layer_client.h" #include "cc/picture.h" #include "cc/rendering_stats.h" +#include "skia/ext/analysis_canvas.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkTileGridPicture.h" @@ -101,7 +102,8 @@ void Picture::Raster( gfx::Rect content_rect, float contents_scale) { TRACE_EVENT2("cc", "Picture::Raster", - "width", layer_rect_.width(), "height", layer_rect_.height()); + "layer width", layer_rect_.width(), + "layer height", layer_rect_.height()); DCHECK(picture_); canvas->save(); @@ -113,7 +115,16 @@ void Picture::Raster( } bool Picture::IsCheapInRect(const gfx::Rect& layer_rect) { - return false; + TRACE_EVENT0("cc", "Picture::IsCheapInRect"); + + SkBitmap emptyBitmap; + emptyBitmap.setConfig(SkBitmap::kNo_Config, layer_rect.width(), + layer_rect.height()); + skia::AnalysisDevice device(emptyBitmap); + skia::AnalysisCanvas canvas(&device); + + canvas.drawPicture(*picture_); + return canvas.isCheap(); } void Picture::GatherPixelRefs(const gfx::Rect& layer_rect, diff --git a/cc/picture.h b/cc/picture.h index 44abb9a1793eb6..40644ee97ae9e3 100644 --- a/cc/picture.h +++ b/cc/picture.h @@ -42,6 +42,9 @@ class CC_EXPORT Picture // Apply this contents scale and raster the content rect into the canvas. void Raster(SkCanvas* canvas, gfx::Rect content_rect, float contents_scale); + // Estimate the cost of rasterizing. To predict the cost of a particular + // call to Raster(), pass this the bounds of the canvas that will + // be rastered into. bool IsCheapInRect(const gfx::Rect& layer_rect); void GatherPixelRefs( diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc new file mode 100644 index 00000000000000..72b9eeb987bdc0 --- /dev/null +++ b/skia/ext/analysis_canvas.cc @@ -0,0 +1,190 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/debug/trace_event.h" +#include "skia/ext/analysis_canvas.h" +#include "third_party/skia/include/core/SkDevice.h" +#include "third_party/skia/include/core/SkDraw.h" +#include "third_party/skia/include/core/SkRRect.h" +#include "ui/gfx/rect_conversions.h" + +namespace { + +// FIXME: Arbitrary number. Requires tuning & experimentation. +// Probably requires per-platform tuning; N10 average draw call takes +// 25x as long as Z620. +const int gPictureCostThreshold = 1000; + +} + +namespace skia { + +AnalysisDevice::AnalysisDevice(const SkBitmap& bm) + : INHERITED(bm) + , estimatedCost_(0) { + +} + +AnalysisDevice::~AnalysisDevice() { + +} + +int AnalysisDevice::getEstimatedCost() const { + return estimatedCost_; +} + +void AnalysisDevice::clear(SkColor color) { + ++estimatedCost_; +} + +void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { + ++estimatedCost_; +} + +void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, + size_t count, const SkPoint[], + const SkPaint& paint) { + ++estimatedCost_; +} + +void AnalysisDevice::drawRect(const SkDraw&, const SkRect& r, + const SkPaint& paint) { + // FIXME: if there's a pending image decode & resize, more expensive + if (paint.getMaskFilter()) { + estimatedCost_ += 300; + } + ++estimatedCost_; +} + +void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, + const SkPaint& paint) { + ++estimatedCost_; +} + +void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, + const SkPaint& paint, + 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 + // we expect it to apply to all path stroking modes. + if (paint.getMaskFilter()) { + estimatedCost_ += 300; + } + ++estimatedCost_; +} + +void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, + const SkIRect* srcRectOrNull, + const SkMatrix& matrix, const SkPaint& paint) + { + ++estimatedCost_; +} + +void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, + int x, int y, const SkPaint& paint) { + ++estimatedCost_; +} + +void AnalysisDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, + const SkRect* srcOrNull, const SkRect& dst, + const SkPaint& paint) { + ++estimatedCost_; +} + + +void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) + { + ++estimatedCost_; +} + +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_; +} + +void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) { + ++estimatedCost_; +} + +#ifdef SK_BUILD_FOR_ANDROID +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_; +} +#endif + +void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, + int vertexCount, + const SkPoint verts[], const SkPoint texs[], + const SkColor colors[], SkXfermode* xmode, + const uint16_t indices[], int indexCount, + const SkPaint& paint) { + ++estimatedCost_; +} + +void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, + const SkPaint&) { + ++estimatedCost_; +} + + + + +AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) + : INHERITED(device) { + +} + +AnalysisCanvas::~AnalysisCanvas() { +} + + +bool AnalysisCanvas::isCheap() const { + return getEstimatedCost() < gPictureCostThreshold; +} + +int AnalysisCanvas::getEstimatedCost() const { + return (static_cast(getDevice()))->getEstimatedCost(); +} + + +bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, + bool doAA) { + return INHERITED::clipRect(rect, op, doAA); +} + +bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, + bool doAA) { + return INHERITED::clipRect(path.getBounds(), op, doAA); +} + +bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, + bool doAA) { + return INHERITED::clipRect(rrect.getBounds(), op, doAA); +} + +int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint*, + SkCanvas::SaveFlags flags) { + // Actually saving a layer here could cause a new bitmap to be created + // and real rendering to occur. + int count = SkCanvas::save(flags); + if (bounds) { + INHERITED::clipRectBounds(bounds, flags, NULL); + } + return count; +} + +} // namespace skia + + diff --git a/skia/ext/analysis_canvas.h b/skia/ext/analysis_canvas.h new file mode 100644 index 00000000000000..e2eedd2fddd121 --- /dev/null +++ b/skia/ext/analysis_canvas.h @@ -0,0 +1,113 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SKIA_EXT_ANALYSIS_CANVAS_H_ +#define SKIA_EXT_ANALYSIS_CANVAS_H_ + +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkDevice.h" + +namespace skia { + +class AnalysisDevice; + +// Does not render anything, but gathers statistics about a region +// (specified as a clip rectangle) of an SkPicture as the picture is +// played back through it. +// To use: create a SkBitmap with kNo_Config, create an AnalysisDevice +// using that bitmap, and create an AnalysisCanvas using the device. +// Play a picture into the canvas, and then check isCheap(). +class SK_API AnalysisCanvas : public SkCanvas { + public: + AnalysisCanvas(AnalysisDevice*); + virtual ~AnalysisCanvas(); + + // Returns true if the estimated cost of drawing is below an + // arbitrary threshold. + bool isCheap() const; + + // Returns the estimated cost of drawing, in arbitrary units. + int getEstimatedCost() const; + + virtual bool clipRect(const SkRect& rect, + SkRegion::Op op = SkRegion::kIntersect_Op, + bool doAntiAlias = false) OVERRIDE; + virtual bool clipPath(const SkPath& path, + SkRegion::Op op = SkRegion::kIntersect_Op, + bool doAntiAlias = false) OVERRIDE; + virtual bool clipRRect(const SkRRect& rrect, + SkRegion::Op op = SkRegion::kIntersect_Op, + bool doAntiAlias = false) OVERRIDE; + + virtual int saveLayer(const SkRect* bounds, const SkPaint*, + SkCanvas::SaveFlags flags) OVERRIDE; + private: + typedef SkCanvas INHERITED; +}; + +class SK_API AnalysisDevice : public SkDevice { + public: + AnalysisDevice(const SkBitmap& bm); + virtual ~AnalysisDevice(); + + int getEstimatedCost() const; + + protected: + virtual void clear(SkColor color) OVERRIDE; + virtual void drawPaint(const SkDraw&, const SkPaint& paint) OVERRIDE; + virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, + size_t count, const SkPoint[], + const SkPaint& paint) OVERRIDE; + virtual void drawRect(const SkDraw&, const SkRect& r, + const SkPaint& paint) OVERRIDE; + virtual void drawOval(const SkDraw&, const SkRect& oval, + const SkPaint& paint) OVERRIDE; + virtual void drawPath(const SkDraw&, const SkPath& path, + const SkPaint& paint, + const SkMatrix* prePathMatrix = NULL, + bool pathIsMutable = false) OVERRIDE; + virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, + const SkIRect* srcRectOrNull, + const SkMatrix& matrix, const SkPaint& paint) + OVERRIDE; + virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, + int x, int y, const SkPaint& paint) OVERRIDE; + virtual void drawBitmapRect(const SkDraw&, const SkBitmap&, + const SkRect* srcOrNull, const SkRect& dst, + const SkPaint& paint) OVERRIDE; + virtual void drawText(const SkDraw&, const void* text, size_t len, + SkScalar x, SkScalar y, const SkPaint& paint) + OVERRIDE; + virtual void drawPosText(const SkDraw& draw, const void* text, size_t len, + const SkScalar pos[], SkScalar constY, + int scalarsPerPos, const SkPaint& paint) OVERRIDE; + virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) OVERRIDE; +#ifdef SK_BUILD_FOR_ANDROID + virtual void drawPosTextOnPath(const SkDraw& draw, const void* text, + size_t len, + const SkPoint pos[], const SkPaint& paint, + const SkPath& path, const SkMatrix* matrix) + OVERRIDE; +#endif + virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, + int vertexCount, + const SkPoint verts[], const SkPoint texs[], + const SkColor colors[], SkXfermode* xmode, + const uint16_t indices[], int indexCount, + const SkPaint& paint) OVERRIDE; + virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y, + const SkPaint&) OVERRIDE; + + int estimatedCost_; + + private: + typedef SkDevice INHERITED; +}; + +} // namespace skia + +#endif // SKIA_EXT_ANALYSIS_CANVAS_H_ + diff --git a/skia/skia.gyp b/skia/skia.gyp index a20e4be78c3386..f8bad831332675 100644 --- a/skia/skia.gyp +++ b/skia/skia.gyp @@ -148,6 +148,8 @@ '../third_party/skia/include/utils/SkNullCanvas.h', '../third_party/skia/include/utils/SkPictureUtils.h', + 'ext/analysis_canvas.cc', + 'ext/analysis_canvas.h', 'ext/bitmap_platform_device.h', 'ext/bitmap_platform_device_android.cc', 'ext/bitmap_platform_device_android.h',