0

Make PicturePile pile.

This follows a similar policy as Android browser:

- If an invalidate only intersects the base plus at most one non-base SkPicture, then it creates a new SkPicture of that size.
- If an invalidate intersects two or more non-base SkPictures, then a new SkPicture is created at the top of the pile, sized to the union of the invalidate plus the bounds of all the intersecting pictures.
- Whenever new picture's area fully contains an existing picture, that old picture is destroyed.
- If an SkPicture's area would be >70% of the base, the pile is
  destroyed and the base SkPicture is recreated.

During the invalidate pass, invalidated pictures are represented as
Pictures with a size but no recording.  Then all the blank pictures
are filled in at the end of the Update().

BUG=163429

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170917 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
aelias@chromium.org
2012-12-04 09:51:20 +00:00
parent c17ca9d20b
commit c97dfc6811
6 changed files with 112 additions and 55 deletions

@ -11,11 +11,12 @@
namespace cc {
scoped_refptr<Picture> Picture::Create() {
return make_scoped_refptr(new Picture());
scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
return make_scoped_refptr(new Picture(layer_rect));
}
Picture::Picture() {
Picture::Picture(gfx::Rect layer_rect)
: layer_rect_(layer_rect) {
}
Picture::Picture(const skia::RefPtr<SkPicture>& picture,
@ -29,7 +30,7 @@ Picture::Picture(const skia::RefPtr<SkPicture>& picture,
Picture::~Picture() {
}
scoped_refptr<Picture> Picture::Clone() {
scoped_refptr<Picture> Picture::Clone() const {
// SkPicture is not thread-safe to rasterize with, so return a thread-safe
// clone of it.
DCHECK(picture_);
@ -37,7 +38,7 @@ scoped_refptr<Picture> Picture::Clone() {
return make_scoped_refptr(new Picture(clone, layer_rect_, opaque_rect_));
}
void Picture::Record(ContentLayerClient* painter, gfx::Rect layer_rect,
void Picture::Record(ContentLayerClient* painter,
RenderingStats& stats) {
TRACE_EVENT0("cc", "Picture::Record");
@ -46,37 +47,36 @@ void Picture::Record(ContentLayerClient* painter, gfx::Rect layer_rect,
picture_ = skia::AdoptRef(new SkPicture);
SkCanvas* canvas = picture_->beginRecording(
layer_rect.width(),
layer_rect.height(),
layer_rect_.width(),
layer_rect_.height(),
SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
canvas->save();
canvas->translate(SkFloatToScalar(-layer_rect.x()),
SkFloatToScalar(-layer_rect.y()));
canvas->translate(SkFloatToScalar(-layer_rect_.x()),
SkFloatToScalar(-layer_rect_.y()));
SkPaint paint;
paint.setAntiAlias(false);
paint.setXfermodeMode(SkXfermode::kClear_Mode);
SkRect layer_skrect = SkRect::MakeXYWH(layer_rect.x(),
layer_rect.y(),
layer_rect.width(),
layer_rect.height());
SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
layer_rect_.y(),
layer_rect_.width(),
layer_rect_.height());
canvas->drawRect(layer_skrect, paint);
canvas->clipRect(layer_skrect);
gfx::RectF opaque_layer_rect;
base::TimeTicks beginPaintTime = base::TimeTicks::Now();
painter->paintContents(canvas, layer_rect, opaque_layer_rect);
painter->paintContents(canvas, layer_rect_, opaque_layer_rect);
double delta = (base::TimeTicks::Now() - beginPaintTime).InSecondsF();
stats.totalPaintTimeInSeconds += delta;
stats.totalPixelsPainted += layer_rect.width() *
layer_rect.height();
stats.totalPixelsPainted += layer_rect_.width() *
layer_rect_.height();
canvas->restore();
picture_->endRecording();
opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
layer_rect_ = layer_rect;
}
void Picture::Raster(SkCanvas* canvas) {

@ -20,24 +20,27 @@ struct RenderingStats;
class CC_EXPORT Picture
: public base::RefCountedThreadSafe<Picture> {
public:
static scoped_refptr<Picture> Create();
static scoped_refptr<Picture> Create(gfx::Rect layer_rect);
const gfx::Rect& LayerRect() const { return layer_rect_; }
const gfx::Rect& OpaqueRect() const { return opaque_rect_; }
// Make a thread-safe clone for rasterizing with.
scoped_refptr<Picture> Clone();
scoped_refptr<Picture> Clone() const;
// Record a paint operation. To be able to safely use this SkPicture for
// playback on a different thread this can only be called once.
void Record(ContentLayerClient*, gfx::Rect layer_rect, RenderingStats&);
void Record(ContentLayerClient*, RenderingStats&);
// Has Record() been called yet?
bool HasRecording() const { return picture_.get(); }
// Raster this Picture's layer_rect into the given canvas.
// Assumes contentsScale have already been applied.
void Raster(SkCanvas* canvas);
private:
Picture();
Picture(gfx::Rect layer_rect);
// This constructor assumes SkPicture is already ref'd and transfers
// ownership to this picture.
Picture(const skia::RefPtr<SkPicture>&,

@ -7,6 +7,15 @@
#include "cc/picture_pile.h"
#include "cc/picture_pile_impl.h"
namespace {
// Maximum number of pictures that can overlap before we collapse them into
// a larger one.
const int kMaxOverlapping = 2;
// Maximum percentage area of the base picture another picture in the pile
// can be. If higher, we destroy the pile and recreate from scratch.
const float kResetThreshold = 0.7f;
}
namespace cc {
PicturePile::PicturePile() {
@ -15,44 +24,80 @@ PicturePile::PicturePile() {
PicturePile::~PicturePile() {
}
class OutOfBoundsPredicate {
public:
OutOfBoundsPredicate(gfx::Size size) : layer_rect_(gfx::Point(), size) { }
bool operator()(const scoped_refptr<Picture>& picture) {
return !picture->LayerRect().Intersects(layer_rect_);
}
gfx::Rect layer_rect_;
};
void PicturePile::Resize(gfx::Size size) {
// Remove pictures that aren't in bounds anymore.
if (size.width() < size_.width() || size.height() < size_.height()) {
OutOfBoundsPredicate oob(size);
pile_.erase(std::remove_if(pile_.begin(), pile_.end(), oob), pile_.end());
}
if (size_ == size)
return;
pile_.clear();
size_ = size;
}
void PicturePile::Update(
ContentLayerClient* painter,
const Region&,
const Region& invalidation,
RenderingStats& stats) {
// TODO(enne): Add things to the pile, consolidate if needed, etc...
// TODO(enne): Only re-record invalidated areas.
// TODO(enne): Also re-record areas that have been newly exposed by resize.
if (pile_.empty()) {
ResetPile(painter, stats);
return;
}
// Always re-record the entire layer into a single picture, just to get
// this class up and running.
for (Region::Iterator i(invalidation); i.has_rect(); i.next())
InvalidateRect(i.rect());
for (Pile::iterator i = pile_.begin(); i != pile_.end(); ++i) {
if (!(*i)->HasRecording())
(*i)->Record(painter, stats);
}
}
class FullyContainedPredicate {
public:
FullyContainedPredicate(gfx::Rect rect) : layer_rect_(rect) { }
bool operator()(const scoped_refptr<Picture>& picture) {
return layer_rect_.Contains(picture->LayerRect());
}
gfx::Rect layer_rect_;
};
void PicturePile::InvalidateRect(gfx::Rect invalidation) {
if (invalidation.IsEmpty())
return;
std::vector<Pile::iterator> overlaps;
for (Pile::iterator i = pile_.begin(); i != pile_.end(); ++i) {
if ((*i)->LayerRect().Contains(invalidation) && !(*i)->HasRecording())
return;
if ((*i)->LayerRect().Intersects(invalidation) && i != pile_.begin())
overlaps.push_back(i);
}
gfx::Rect picture_rect = invalidation;
if (overlaps.size() >= kMaxOverlapping) {
for (size_t j = 0; j < overlaps.size(); j++)
picture_rect = gfx::UnionRects(picture_rect, (*overlaps[j])->LayerRect());
}
if (picture_rect.size().GetArea() / static_cast<float>(size_.GetArea()) >
kResetThreshold)
picture_rect = gfx::Rect(size_);
FullyContainedPredicate pred(picture_rect);
pile_.erase(std::remove_if(pile_.begin(), pile_.end(), pred), pile_.end());
pile_.push_back(Picture::Create(picture_rect));
}
void PicturePile::ResetPile(ContentLayerClient* painter,
RenderingStats& stats) {
pile_.clear();
pile_.push_back(Picture::Create());
pile_[0]->Record(painter, gfx::Rect(gfx::Point(), size_), stats);
scoped_refptr<Picture> base_picture = Picture::Create(gfx::Rect(size_));
base_picture->Record(painter, stats);
pile_.push_back(base_picture);
}
void PicturePile::PushPropertiesTo(PicturePileImpl* other) {
other->pile_.resize(pile_.size());
for (size_t i = 0; i < pile_.size(); ++i)
other->pile_[i] = pile_[i];
other->pile_ = pile_;
}
} // namespace cc

@ -5,6 +5,8 @@
#ifndef CC_PICTURE_PILE_H_
#define CC_PICTURE_PILE_H_
#include <list>
#include "base/basictypes.h"
#include "cc/cc_export.h"
#include "cc/picture.h"
@ -38,7 +40,13 @@ public:
void PushPropertiesTo(PicturePileImpl* other);
private:
std::vector<scoped_refptr<Picture> > pile_;
friend class PicturePileImpl;
void InvalidateRect(gfx::Rect invalidation);
void ResetPile(ContentLayerClient* painter, RenderingStats& stats);
typedef std::list<scoped_refptr<Picture> > Pile;
Pile pile_;
gfx::Size size_;
DISALLOW_COPY_AND_ASSIGN(PicturePile);

@ -23,9 +23,9 @@ PicturePileImpl::~PicturePileImpl() {
scoped_refptr<PicturePileImpl> PicturePileImpl::CloneForDrawing() const {
TRACE_EVENT0("cc", "PicturePileImpl::CloneForDrawing");
scoped_refptr<PicturePileImpl> clone = Create();
clone->pile_.resize(pile_.size());
for (size_t i = 0; i < pile_.size(); ++i)
clone->pile_[i] = pile_[i]->Clone();
for (PicturePile::Pile::const_iterator i = pile_.begin();
i != pile_.end(); ++i)
clone->pile_.push_back((*i)->Clone());
return clone;
}
@ -40,10 +40,11 @@ void PicturePileImpl::Raster(SkCanvas* canvas, gfx::Rect rect,
SkRect layer_skrect = SkRect::MakeXYWH(rect.x(), rect.y(),
rect.width(), rect.height());
canvas->clipRect(layer_skrect);
for (size_t i = 0; i < pile_.size(); ++i) {
if (!pile_[i]->LayerRect().Intersects(rect))
for (PicturePile::Pile::const_iterator i = pile_.begin();
i != pile_.end(); ++i) {
if (!(*i)->LayerRect().Intersects(rect))
continue;
pile_[i]->Raster(canvas);
(*i)->Raster(canvas);
SkISize deviceSize = canvas->getDeviceSize();
stats->totalPixelsRasterized += deviceSize.width() * deviceSize.height();

@ -9,11 +9,11 @@
#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
#include "cc/picture.h"
#include "cc/picture_pile.h"
#include "cc/scoped_ptr_vector.h"
#include "ui/gfx/rect.h"
namespace cc {
class PicturePile;
struct RenderingStats;
class CC_EXPORT PicturePileImpl : public base::RefCounted<PicturePileImpl> {
@ -34,7 +34,7 @@ private:
PicturePileImpl();
~PicturePileImpl();
std::vector<scoped_refptr<Picture> > pile_;
PicturePile::Pile pile_;
friend class base::RefCounted<PicturePileImpl>;
DISALLOW_COPY_AND_ASSIGN(PicturePileImpl);