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:
@ -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) {
|
||||
|
11
cc/picture.h
11
cc/picture.h
@ -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);
|
||||
|
Reference in New Issue
Block a user