Skip to content

Commit

Permalink
Implementation for cc::Picture::IsCheapInRect().
Browse files Browse the repository at this point in the history
Minimal implementation for cc::Picture::IsCheapInRect() with new
classes skia::AnalysisCanvas and skia::AnalysisDevice.
Supercedes http://codereview.chromium.org/12184010/.

Based on GatherPixelRefs.

Not a good implementation yet, but it does seem to count draw calls
and is right more often than a stopped clock. I'm not happy with
clipping/culling; something is going very wrong there.

TBR=nduca,junov,tomhudson
CC=skyostil
BUG=173426


Review URL: https://chromiumcodereview.appspot.com/12213018

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@181369 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
tomhudson@chromium.org committed Feb 7, 2013
1 parent a09a58d commit c931465
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 2 deletions.
15 changes: 13 additions & 2 deletions cc/picture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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();
Expand All @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions cc/picture.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
190 changes: 190 additions & 0 deletions skia/ext/analysis_canvas.cc
Original file line number Diff line number Diff line change
@@ -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<AnalysisDevice*>(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


113 changes: 113 additions & 0 deletions skia/ext/analysis_canvas.h
Original file line number Diff line number Diff line change
@@ -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_

2 changes: 2 additions & 0 deletions skia/skia.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit c931465

Please sign in to comment.