summaryrefslogtreecommitdiffstats
path: root/chromium/cc/resources/picture.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/resources/picture.cc')
-rw-r--r--chromium/cc/resources/picture.cc228
1 files changed, 172 insertions, 56 deletions
diff --git a/chromium/cc/resources/picture.cc b/chromium/cc/resources/picture.cc
index 8c3be9c3bca..a19fd33f3a0 100644
--- a/chromium/cc/resources/picture.cc
+++ b/chromium/cc/resources/picture.cc
@@ -16,12 +16,14 @@
#include "cc/debug/traced_picture.h"
#include "cc/debug/traced_value.h"
#include "cc/layers/content_layer_client.h"
-#include "skia/ext/lazy_pixel_ref_utils.h"
+#include "skia/ext/pixel_ref_utils.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkDrawFilter.h"
#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/utils/SkNullCanvas.h"
#include "third_party/skia/include/utils/SkPictureUtils.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/codec/png_codec.h"
@@ -81,11 +83,24 @@ bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
} // namespace
-scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
- return make_scoped_refptr(new Picture(layer_rect));
+scoped_refptr<Picture> Picture::Create(
+ const gfx::Rect& layer_rect,
+ ContentLayerClient* client,
+ const SkTileGridFactory::TileGridInfo& tile_grid_info,
+ bool gather_pixel_refs,
+ int num_raster_threads,
+ RecordingMode recording_mode) {
+ scoped_refptr<Picture> picture = make_scoped_refptr(new Picture(layer_rect));
+
+ picture->Record(client, tile_grid_info, recording_mode);
+ if (gather_pixel_refs)
+ picture->GatherPixelRefs(tile_grid_info);
+ picture->CloneForDrawing(num_raster_threads);
+
+ return picture;
}
-Picture::Picture(gfx::Rect layer_rect)
+Picture::Picture(const gfx::Rect& layer_rect)
: layer_rect_(layer_rect),
cell_size_(layer_rect.size()) {
// Instead of recording a trace event for object creation here, we wait for
@@ -152,8 +167,8 @@ scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
}
Picture::Picture(SkPicture* picture,
- gfx::Rect layer_rect,
- gfx::Rect opaque_rect) :
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& opaque_rect) :
layer_rect_(layer_rect),
opaque_rect_(opaque_rect),
picture_(skia::AdoptRef(picture)),
@@ -161,8 +176,8 @@ Picture::Picture(SkPicture* picture,
}
Picture::Picture(const skia::RefPtr<SkPicture>& picture,
- gfx::Rect layer_rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& opaque_rect,
const PixelRefMap& pixel_refs) :
layer_rect_(layer_rect),
opaque_rect_(opaque_rect),
@@ -176,48 +191,111 @@ Picture::~Picture() {
TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
}
-scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread(
- unsigned thread_index) const {
+Picture* Picture::GetCloneForDrawingOnThread(unsigned thread_index) {
+ // We don't need clones to draw from multiple threads with SkRecord.
+ if (playback_) {
+ return this;
+ }
+
// SkPicture is not thread-safe to rasterize with, this returns a clone
// to rasterize with on a specific thread.
- CHECK_GT(clones_.size(), thread_index);
- return clones_[thread_index];
+ CHECK_GE(clones_.size(), thread_index);
+ return thread_index == clones_.size() ? this : clones_[thread_index].get();
+}
+
+bool Picture::IsSuitableForGpuRasterization() const {
+ DCHECK(picture_);
+
+ // TODO(alokp): SkPicture::suitableForGpuRasterization needs a GrContext.
+ // Ideally this GrContext should be the same as that for rasterizing this
+ // picture. But we are on the main thread while the rasterization context
+ // may be on the compositor or raster thread.
+ // SkPicture::suitableForGpuRasterization is not implemented yet.
+ // Pass a NULL context for now and discuss with skia folks if the context
+ // is really needed.
+ return picture_->suitableForGpuRasterization(NULL);
}
void Picture::CloneForDrawing(int num_threads) {
TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
+ // We don't need clones to draw from multiple threads with SkRecord.
+ if (playback_) {
+ return;
+ }
+
DCHECK(picture_);
- scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]);
- picture_->clone(&clones[0], num_threads);
-
- clones_.clear();
- for (int i = 0; i < num_threads; i++) {
- scoped_refptr<Picture> clone = make_scoped_refptr(
- new Picture(skia::AdoptRef(new SkPicture(clones[i])),
- layer_rect_,
- opaque_rect_,
- pixel_refs_));
- clones_.push_back(clone);
-
- clone->EmitTraceSnapshotAlias(this);
+ DCHECK(clones_.empty());
+
+ // We can re-use this picture for one raster worker thread.
+ raster_thread_checker_.DetachFromThread();
+
+ if (num_threads > 1) {
+ scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads - 1]);
+ picture_->clone(&clones[0], num_threads - 1);
+
+ for (int i = 0; i < num_threads - 1; i++) {
+ scoped_refptr<Picture> clone = make_scoped_refptr(
+ new Picture(skia::AdoptRef(new SkPicture(clones[i])),
+ layer_rect_,
+ opaque_rect_,
+ pixel_refs_));
+ clones_.push_back(clone);
+
+ clone->EmitTraceSnapshotAlias(this);
+ clone->raster_thread_checker_.DetachFromThread();
+ }
}
}
void Picture::Record(ContentLayerClient* painter,
- const SkTileGridPicture::TileGridInfo& tile_grid_info) {
- TRACE_EVENT1("cc", "Picture::Record",
- "data", AsTraceableRecordData());
-
+ const SkTileGridFactory::TileGridInfo& tile_grid_info,
+ RecordingMode recording_mode) {
+ TRACE_EVENT2("cc",
+ "Picture::Record",
+ "data",
+ AsTraceableRecordData(),
+ "recording_mode",
+ recording_mode);
+
+ DCHECK(!picture_);
DCHECK(!tile_grid_info.fTileInterval.isEmpty());
- picture_ = skia::AdoptRef(new SkTileGridPicture(
- layer_rect_.width(), layer_rect_.height(), tile_grid_info));
- SkCanvas* canvas = picture_->beginRecording(
- layer_rect_.width(),
- layer_rect_.height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag |
- SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+ SkTileGridFactory factory(tile_grid_info);
+ SkPictureRecorder recorder;
+
+ scoped_ptr<EXPERIMENTAL::SkRecording> recording;
+
+ skia::RefPtr<SkCanvas> canvas;
+ canvas = skia::SharePtr(recorder.beginRecording(
+ layer_rect_.width(), layer_rect_.height(), &factory));
+
+ ContentLayerClient::GraphicsContextStatus graphics_context_status =
+ ContentLayerClient::GRAPHICS_CONTEXT_ENABLED;
+
+ switch (recording_mode) {
+ case RECORD_NORMALLY:
+ // Already setup for normal recording.
+ break;
+ case RECORD_WITH_SK_NULL_CANVAS:
+ canvas = skia::AdoptRef(SkCreateNullCanvas());
+ break;
+ case RECORD_WITH_PAINTING_DISABLED:
+ // We pass a disable flag through the paint calls when perfromance
+ // testing (the only time this case should ever arise) when we want to
+ // prevent the Blink GraphicsContext object from consuming any compute
+ // time.
+ canvas = skia::AdoptRef(SkCreateNullCanvas());
+ graphics_context_status = ContentLayerClient::GRAPHICS_CONTEXT_DISABLED;
+ break;
+ case RECORD_WITH_SKRECORD:
+ recording.reset(new EXPERIMENTAL::SkRecording(layer_rect_.width(),
+ layer_rect_.height()));
+ canvas = skia::SharePtr(recording->canvas());
+ break;
+ default:
+ NOTREACHED();
+ }
canvas->save();
canvas->translate(SkFloatToScalar(-layer_rect_.x()),
@@ -230,11 +308,19 @@ void Picture::Record(ContentLayerClient* painter,
canvas->clipRect(layer_skrect);
gfx::RectF opaque_layer_rect;
-
- painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect);
+ painter->PaintContents(
+ canvas.get(), layer_rect_, &opaque_layer_rect, graphics_context_status);
canvas->restore();
- picture_->endRecording();
+ picture_ = skia::AdoptRef(recorder.endRecording());
+ DCHECK(picture_);
+
+ if (recording) {
+ // SkRecording requires it's the only one holding onto canvas before we
+ // may call releasePlayback(). (This helps enforce thread-safety.)
+ canvas.clear();
+ playback_.reset(recording->releasePlayback());
+ }
opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
@@ -242,12 +328,13 @@ void Picture::Record(ContentLayerClient* painter,
}
void Picture::GatherPixelRefs(
- const SkTileGridPicture::TileGridInfo& tile_grid_info) {
+ const SkTileGridFactory::TileGridInfo& tile_grid_info) {
TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
"width", layer_rect_.width(),
"height", layer_rect_.height());
DCHECK(picture_);
+ DCHECK(pixel_refs_.empty());
if (!WillPlayBackBitmaps())
return;
cell_size_ = gfx::Size(
@@ -263,9 +350,9 @@ void Picture::GatherPixelRefs(
int max_x = 0;
int max_y = 0;
- skia::LazyPixelRefList pixel_refs;
- skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs);
- for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin();
+ skia::DiscardablePixelRefList pixel_refs;
+ skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
+ for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
it != pixel_refs.end();
++it) {
gfx::Point min(
@@ -282,7 +369,7 @@ void Picture::GatherPixelRefs(
for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
PixelRefMapKey key(x, y);
- pixel_refs_[key].push_back(it->lazy_pixel_ref);
+ pixel_refs_[key].push_back(it->pixel_ref);
}
}
@@ -301,6 +388,8 @@ int Picture::Raster(
SkDrawPictureCallback* callback,
const Region& negated_content_region,
float contents_scale) {
+ if (!playback_)
+ DCHECK(raster_thread_checker_.CalledOnValidThread());
TRACE_EVENT_BEGIN1(
"cc",
"Picture::Raster",
@@ -316,7 +405,11 @@ int Picture::Raster(
canvas->scale(contents_scale, contents_scale);
canvas->translate(layer_rect_.x(), layer_rect_.y());
- picture_->draw(canvas, callback);
+ if (playback_) {
+ playback_->draw(canvas);
+ } else {
+ picture_->draw(canvas, callback);
+ }
SkIRect bounds;
canvas->getClipDeviceBounds(&bounds);
canvas->restore();
@@ -327,10 +420,16 @@ int Picture::Raster(
}
void Picture::Replay(SkCanvas* canvas) {
+ if (!playback_)
+ DCHECK(raster_thread_checker_.CalledOnValidThread());
TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
DCHECK(picture_);
- picture_->draw(canvas);
+ if (playback_) {
+ playback_->draw(canvas);
+ } else {
+ picture_->draw(canvas);
+ }
SkIRect bounds;
canvas->getClipDeviceBounds(&bounds);
TRACE_EVENT_END1("cc", "Picture::Replay",
@@ -340,8 +439,20 @@ void Picture::Replay(SkCanvas* canvas) {
scoped_ptr<base::Value> Picture::AsValue() const {
SkDynamicMemoryWStream stream;
- // Serialize the picture.
- picture_->serialize(&stream, &EncodeBitmap);
+ if (playback_) {
+ // SkPlayback can't serialize itself, so re-record into an SkPicture.
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas(skia::SharePtr(recorder.beginRecording(
+ layer_rect_.width(),
+ layer_rect_.height(),
+ NULL))); // Default (no) bounding-box hierarchy is fastest.
+ playback_->draw(canvas.get());
+ skia::RefPtr<SkPicture> picture(skia::AdoptRef(recorder.endRecording()));
+ picture->serialize(&stream, &EncodeBitmap);
+ } else {
+ // Serialize the picture.
+ picture_->serialize(&stream, &EncodeBitmap);
+ }
// Encode the picture as base64.
scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
@@ -358,14 +469,19 @@ scoped_ptr<base::Value> Picture::AsValue() const {
return res.PassAs<base::Value>();
}
-void Picture::EmitTraceSnapshot() {
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
+void Picture::EmitTraceSnapshot() const {
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
+ "devtools.timeline.picture"),
+ "cc::Picture",
+ this,
+ TracedPicture::AsTraceablePicture(this));
}
-void Picture::EmitTraceSnapshotAlias(Picture* original) {
+void Picture::EmitTraceSnapshotAlias(Picture* original) const {
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
+ "devtools.timeline.picture"),
"cc::Picture",
this,
TracedPicture::AsTraceablePictureAlias(original));
@@ -385,7 +501,7 @@ Picture::PixelRefIterator::PixelRefIterator()
}
Picture::PixelRefIterator::PixelRefIterator(
- gfx::Rect query_rect,
+ const gfx::Rect& rect,
const Picture* picture)
: picture_(picture),
current_pixel_refs_(empty_pixel_refs_.Pointer()),
@@ -394,6 +510,7 @@ Picture::PixelRefIterator::PixelRefIterator(
gfx::Size cell_size = picture->cell_size_;
DCHECK(!cell_size.IsEmpty());
+ gfx::Rect query_rect(rect);
// Early out if the query rect doesn't intersect this picture.
if (!query_rect.Intersects(layer_rect)) {
min_point_ = gfx::Point(0, 0);
@@ -482,8 +599,7 @@ scoped_refptr<base::debug::ConvertableToTraceFormat>
Picture::AsTraceableRecordData() const {
scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
record_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
- record_data->SetInteger("width", layer_rect_.width());
- record_data->SetInteger("height", layer_rect_.height());
+ record_data->Set("layer_rect", MathUtil::AsValue(layer_rect_).release());
return TracedValue::FromValue(record_data.release());
}