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 {
|
namespace cc {
|
||||||
|
|
||||||
scoped_refptr<Picture> Picture::Create() {
|
scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
|
||||||
return make_scoped_refptr(new Picture());
|
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,
|
Picture::Picture(const skia::RefPtr<SkPicture>& picture,
|
||||||
@ -29,7 +30,7 @@ Picture::Picture(const skia::RefPtr<SkPicture>& picture,
|
|||||||
Picture::~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
|
// SkPicture is not thread-safe to rasterize with, so return a thread-safe
|
||||||
// clone of it.
|
// clone of it.
|
||||||
DCHECK(picture_);
|
DCHECK(picture_);
|
||||||
@ -37,7 +38,7 @@ scoped_refptr<Picture> Picture::Clone() {
|
|||||||
return make_scoped_refptr(new Picture(clone, layer_rect_, opaque_rect_));
|
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) {
|
RenderingStats& stats) {
|
||||||
TRACE_EVENT0("cc", "Picture::Record");
|
TRACE_EVENT0("cc", "Picture::Record");
|
||||||
|
|
||||||
@ -46,37 +47,36 @@ void Picture::Record(ContentLayerClient* painter, gfx::Rect layer_rect,
|
|||||||
picture_ = skia::AdoptRef(new SkPicture);
|
picture_ = skia::AdoptRef(new SkPicture);
|
||||||
|
|
||||||
SkCanvas* canvas = picture_->beginRecording(
|
SkCanvas* canvas = picture_->beginRecording(
|
||||||
layer_rect.width(),
|
layer_rect_.width(),
|
||||||
layer_rect.height(),
|
layer_rect_.height(),
|
||||||
SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
|
SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
|
||||||
|
|
||||||
canvas->save();
|
canvas->save();
|
||||||
canvas->translate(SkFloatToScalar(-layer_rect.x()),
|
canvas->translate(SkFloatToScalar(-layer_rect_.x()),
|
||||||
SkFloatToScalar(-layer_rect.y()));
|
SkFloatToScalar(-layer_rect_.y()));
|
||||||
|
|
||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
paint.setAntiAlias(false);
|
paint.setAntiAlias(false);
|
||||||
paint.setXfermodeMode(SkXfermode::kClear_Mode);
|
paint.setXfermodeMode(SkXfermode::kClear_Mode);
|
||||||
SkRect layer_skrect = SkRect::MakeXYWH(layer_rect.x(),
|
SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
|
||||||
layer_rect.y(),
|
layer_rect_.y(),
|
||||||
layer_rect.width(),
|
layer_rect_.width(),
|
||||||
layer_rect.height());
|
layer_rect_.height());
|
||||||
canvas->drawRect(layer_skrect, paint);
|
canvas->drawRect(layer_skrect, paint);
|
||||||
canvas->clipRect(layer_skrect);
|
canvas->clipRect(layer_skrect);
|
||||||
|
|
||||||
gfx::RectF opaque_layer_rect;
|
gfx::RectF opaque_layer_rect;
|
||||||
base::TimeTicks beginPaintTime = base::TimeTicks::Now();
|
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();
|
double delta = (base::TimeTicks::Now() - beginPaintTime).InSecondsF();
|
||||||
stats.totalPaintTimeInSeconds += delta;
|
stats.totalPaintTimeInSeconds += delta;
|
||||||
stats.totalPixelsPainted += layer_rect.width() *
|
stats.totalPixelsPainted += layer_rect_.width() *
|
||||||
layer_rect.height();
|
layer_rect_.height();
|
||||||
|
|
||||||
canvas->restore();
|
canvas->restore();
|
||||||
picture_->endRecording();
|
picture_->endRecording();
|
||||||
|
|
||||||
opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
|
opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
|
||||||
layer_rect_ = layer_rect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Picture::Raster(SkCanvas* canvas) {
|
void Picture::Raster(SkCanvas* canvas) {
|
||||||
|
11
cc/picture.h
11
cc/picture.h
@ -20,24 +20,27 @@ struct RenderingStats;
|
|||||||
class CC_EXPORT Picture
|
class CC_EXPORT Picture
|
||||||
: public base::RefCountedThreadSafe<Picture> {
|
: public base::RefCountedThreadSafe<Picture> {
|
||||||
public:
|
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& LayerRect() const { return layer_rect_; }
|
||||||
const gfx::Rect& OpaqueRect() const { return opaque_rect_; }
|
const gfx::Rect& OpaqueRect() const { return opaque_rect_; }
|
||||||
|
|
||||||
// Make a thread-safe clone for rasterizing with.
|
// 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
|
// Record a paint operation. To be able to safely use this SkPicture for
|
||||||
// playback on a different thread this can only be called once.
|
// 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.
|
// Raster this Picture's layer_rect into the given canvas.
|
||||||
// Assumes contentsScale have already been applied.
|
// Assumes contentsScale have already been applied.
|
||||||
void Raster(SkCanvas* canvas);
|
void Raster(SkCanvas* canvas);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Picture();
|
Picture(gfx::Rect layer_rect);
|
||||||
// This constructor assumes SkPicture is already ref'd and transfers
|
// This constructor assumes SkPicture is already ref'd and transfers
|
||||||
// ownership to this picture.
|
// ownership to this picture.
|
||||||
Picture(const skia::RefPtr<SkPicture>&,
|
Picture(const skia::RefPtr<SkPicture>&,
|
||||||
|
@ -7,6 +7,15 @@
|
|||||||
#include "cc/picture_pile.h"
|
#include "cc/picture_pile.h"
|
||||||
#include "cc/picture_pile_impl.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 {
|
namespace cc {
|
||||||
|
|
||||||
PicturePile::PicturePile() {
|
PicturePile::PicturePile() {
|
||||||
@ -15,44 +24,80 @@ PicturePile::PicturePile() {
|
|||||||
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) {
|
void PicturePile::Resize(gfx::Size size) {
|
||||||
// Remove pictures that aren't in bounds anymore.
|
if (size_ == size)
|
||||||
if (size.width() < size_.width() || size.height() < size_.height()) {
|
return;
|
||||||
OutOfBoundsPredicate oob(size);
|
|
||||||
pile_.erase(std::remove_if(pile_.begin(), pile_.end(), oob), pile_.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
pile_.clear();
|
||||||
size_ = size;
|
size_ = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PicturePile::Update(
|
void PicturePile::Update(
|
||||||
ContentLayerClient* painter,
|
ContentLayerClient* painter,
|
||||||
const Region&,
|
const Region& invalidation,
|
||||||
RenderingStats& stats) {
|
RenderingStats& stats) {
|
||||||
// TODO(enne): Add things to the pile, consolidate if needed, etc...
|
if (pile_.empty()) {
|
||||||
// TODO(enne): Only re-record invalidated areas.
|
ResetPile(painter, stats);
|
||||||
// TODO(enne): Also re-record areas that have been newly exposed by resize.
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Always re-record the entire layer into a single picture, just to get
|
for (Region::Iterator i(invalidation); i.has_rect(); i.next())
|
||||||
// this class up and running.
|
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_.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) {
|
void PicturePile::PushPropertiesTo(PicturePileImpl* other) {
|
||||||
other->pile_.resize(pile_.size());
|
other->pile_ = pile_;
|
||||||
for (size_t i = 0; i < pile_.size(); ++i)
|
|
||||||
other->pile_[i] = pile_[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cc
|
} // namespace cc
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#ifndef CC_PICTURE_PILE_H_
|
#ifndef CC_PICTURE_PILE_H_
|
||||||
#define CC_PICTURE_PILE_H_
|
#define CC_PICTURE_PILE_H_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
#include "cc/cc_export.h"
|
#include "cc/cc_export.h"
|
||||||
#include "cc/picture.h"
|
#include "cc/picture.h"
|
||||||
@ -38,7 +40,13 @@ public:
|
|||||||
void PushPropertiesTo(PicturePileImpl* other);
|
void PushPropertiesTo(PicturePileImpl* other);
|
||||||
|
|
||||||
private:
|
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_;
|
gfx::Size size_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(PicturePile);
|
DISALLOW_COPY_AND_ASSIGN(PicturePile);
|
||||||
|
@ -23,9 +23,9 @@ PicturePileImpl::~PicturePileImpl() {
|
|||||||
scoped_refptr<PicturePileImpl> PicturePileImpl::CloneForDrawing() const {
|
scoped_refptr<PicturePileImpl> PicturePileImpl::CloneForDrawing() const {
|
||||||
TRACE_EVENT0("cc", "PicturePileImpl::CloneForDrawing");
|
TRACE_EVENT0("cc", "PicturePileImpl::CloneForDrawing");
|
||||||
scoped_refptr<PicturePileImpl> clone = Create();
|
scoped_refptr<PicturePileImpl> clone = Create();
|
||||||
clone->pile_.resize(pile_.size());
|
for (PicturePile::Pile::const_iterator i = pile_.begin();
|
||||||
for (size_t i = 0; i < pile_.size(); ++i)
|
i != pile_.end(); ++i)
|
||||||
clone->pile_[i] = pile_[i]->Clone();
|
clone->pile_.push_back((*i)->Clone());
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
@ -40,10 +40,11 @@ void PicturePileImpl::Raster(SkCanvas* canvas, gfx::Rect rect,
|
|||||||
SkRect layer_skrect = SkRect::MakeXYWH(rect.x(), rect.y(),
|
SkRect layer_skrect = SkRect::MakeXYWH(rect.x(), rect.y(),
|
||||||
rect.width(), rect.height());
|
rect.width(), rect.height());
|
||||||
canvas->clipRect(layer_skrect);
|
canvas->clipRect(layer_skrect);
|
||||||
for (size_t i = 0; i < pile_.size(); ++i) {
|
for (PicturePile::Pile::const_iterator i = pile_.begin();
|
||||||
if (!pile_[i]->LayerRect().Intersects(rect))
|
i != pile_.end(); ++i) {
|
||||||
|
if (!(*i)->LayerRect().Intersects(rect))
|
||||||
continue;
|
continue;
|
||||||
pile_[i]->Raster(canvas);
|
(*i)->Raster(canvas);
|
||||||
|
|
||||||
SkISize deviceSize = canvas->getDeviceSize();
|
SkISize deviceSize = canvas->getDeviceSize();
|
||||||
stats->totalPixelsRasterized += deviceSize.width() * deviceSize.height();
|
stats->totalPixelsRasterized += deviceSize.width() * deviceSize.height();
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
#include "base/memory/ref_counted.h"
|
#include "base/memory/ref_counted.h"
|
||||||
#include "cc/cc_export.h"
|
#include "cc/cc_export.h"
|
||||||
#include "cc/picture.h"
|
#include "cc/picture.h"
|
||||||
|
#include "cc/picture_pile.h"
|
||||||
#include "cc/scoped_ptr_vector.h"
|
#include "cc/scoped_ptr_vector.h"
|
||||||
#include "ui/gfx/rect.h"
|
#include "ui/gfx/rect.h"
|
||||||
|
|
||||||
namespace cc {
|
namespace cc {
|
||||||
class PicturePile;
|
|
||||||
struct RenderingStats;
|
struct RenderingStats;
|
||||||
|
|
||||||
class CC_EXPORT PicturePileImpl : public base::RefCounted<PicturePileImpl> {
|
class CC_EXPORT PicturePileImpl : public base::RefCounted<PicturePileImpl> {
|
||||||
@ -34,7 +34,7 @@ private:
|
|||||||
PicturePileImpl();
|
PicturePileImpl();
|
||||||
~PicturePileImpl();
|
~PicturePileImpl();
|
||||||
|
|
||||||
std::vector<scoped_refptr<Picture> > pile_;
|
PicturePile::Pile pile_;
|
||||||
|
|
||||||
friend class base::RefCounted<PicturePileImpl>;
|
friend class base::RefCounted<PicturePileImpl>;
|
||||||
DISALLOW_COPY_AND_ASSIGN(PicturePileImpl);
|
DISALLOW_COPY_AND_ASSIGN(PicturePileImpl);
|
||||||
|
Reference in New Issue
Block a user