[go: nahoru, domu]

blob: a79d886c953063aa9b8728e278f18458a0c2e38b [file] [log] [blame]
// Copyright 2014 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 "cc/paint/display_item_list.h"
#include <stddef.h>
#include <string>
#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "cc/base/math_util.h"
#include "cc/base/render_surface_filters.h"
#include "cc/debug/picture_debug_util.h"
#include "cc/paint/discardable_image_store.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/skia_util.h"
namespace cc {
namespace {
// We don't perform per-layer solid color analysis when there are too many skia
// operations.
const int kOpCountThatIsOkToAnalyze = 10;
bool GetCanvasClipBounds(SkCanvas* canvas, gfx::Rect* clip_bounds) {
SkRect canvas_clip_bounds;
if (!canvas->getLocalClipBounds(&canvas_clip_bounds))
return false;
*clip_bounds = ToEnclosingRect(gfx::SkRectToRectF(canvas_clip_bounds));
return true;
}
} // namespace
DisplayItemList::DisplayItemList() {
visual_rects_.reserve(1024);
begin_paired_indices_.reserve(32);
}
DisplayItemList::~DisplayItemList() = default;
void DisplayItemList::Raster(SkCanvas* canvas,
SkPicture::AbortCallback* callback) const {
gfx::Rect canvas_playback_rect;
if (!GetCanvasClipBounds(canvas, &canvas_playback_rect))
return;
std::vector<size_t> indices = rtree_.Search(canvas_playback_rect);
paint_op_buffer_.Playback(canvas, callback, &indices);
}
void DisplayItemList::GrowCurrentBeginItemVisualRect(
const gfx::Rect& visual_rect) {
if (!begin_paired_indices_.empty())
visual_rects_[begin_paired_indices_.back().first].Union(visual_rect);
}
void DisplayItemList::Finalize() {
TRACE_EVENT0("cc", "DisplayItemList::Finalize");
// If this fails a call to StartPaint() was not ended.
DCHECK(!in_painting_);
// If this fails we had more calls to EndPaintOfPairedBegin() than
// to EndPaintOfPairedEnd().
DCHECK_EQ(0, in_paired_begin_count_);
paint_op_buffer_.ShrinkToFit();
rtree_.Build(visual_rects_);
visual_rects_.clear();
visual_rects_.shrink_to_fit();
begin_paired_indices_.shrink_to_fit();
}
size_t DisplayItemList::BytesUsed() const {
// TODO(jbroman): Does anything else owned by this class substantially
// contribute to memory usage?
// TODO(vmpstr): Probably DiscardableImageMap is worth counting here.
return sizeof(*this) + paint_op_buffer_.bytes_used();
}
bool DisplayItemList::ShouldBeAnalyzedForSolidColor() const {
return op_count() <= kOpCountThatIsOkToAnalyze;
}
void DisplayItemList::EmitTraceSnapshot() const {
bool include_items;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(
TRACE_DISABLED_BY_DEFAULT("cc.debug.display_items"), &include_items);
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
TRACE_DISABLED_BY_DEFAULT("cc.debug.display_items") ","
TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") ","
TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"),
"cc::DisplayItemList", this, CreateTracedValue(include_items));
}
std::unique_ptr<base::trace_event::TracedValue>
DisplayItemList::CreateTracedValue(bool include_items) const {
auto state = base::MakeUnique<base::trace_event::TracedValue>();
state->BeginDictionary("params");
if (include_items) {
state->BeginArray("items");
for (size_t i = 0; i < paint_op_buffer_.size(); ++i) {
state->BeginDictionary();
SkPictureRecorder recorder;
SkCanvas* canvas =
recorder.beginRecording(gfx::RectToSkRect(rtree_.GetBounds()));
std::vector<size_t> indices{i};
paint_op_buffer_.Playback(canvas, nullptr, &indices);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
std::string b64_picture;
PictureDebugUtil::SerializeAsBase64(picture.get(), &b64_picture);
state->SetString("skp64", b64_picture);
state->EndDictionary();
}
state->EndArray(); // "items".
}
MathUtil::AddToTracedValue("layer_rect", rtree_.GetBounds(), state.get());
state->EndDictionary(); // "params".
{
SkPictureRecorder recorder;
gfx::Rect bounds = rtree_.GetBounds();
SkCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(bounds));
canvas->translate(-bounds.x(), -bounds.y());
canvas->clipRect(gfx::RectToSkRect(bounds));
Raster(canvas);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
std::string b64_picture;
PictureDebugUtil::SerializeAsBase64(picture.get(), &b64_picture);
state->SetString("skp64", b64_picture);
}
return state;
}
void DisplayItemList::GenerateDiscardableImagesMetadata() {
// This should be only called once.
DCHECK(image_map_.empty());
if (!paint_op_buffer_.HasDiscardableImages())
return;
gfx::Rect bounds = rtree_.GetBounds();
DiscardableImageMap::ScopedMetadataGenerator generator(
&image_map_, gfx::Size(bounds.right(), bounds.bottom()));
GatherDiscardableImages(generator.image_store());
}
void DisplayItemList::GatherDiscardableImages(
DiscardableImageStore* image_store) const {
image_store->GatherDiscardableImages(&paint_op_buffer_);
}
void DisplayItemList::GetDiscardableImagesInRect(
const gfx::Rect& rect,
float contents_scale,
const gfx::ColorSpace& target_color_space,
std::vector<DrawImage>* images) {
image_map_.GetDiscardableImagesInRect(rect, contents_scale,
target_color_space, images);
}
gfx::Rect DisplayItemList::GetRectForImage(PaintImage::Id image_id) const {
return image_map_.GetRectForImage(image_id);
}
void DisplayItemList::Reset() {
DCHECK(!in_painting_);
DCHECK_EQ(0, in_paired_begin_count_);
rtree_.Reset();
image_map_.Reset();
paint_op_buffer_.Reset();
visual_rects_.clear();
begin_paired_indices_.clear();
current_range_start_ = 0;
in_paired_begin_count_ = 0;
in_painting_ = false;
op_count_ = 0u;
}
sk_sp<PaintRecord> DisplayItemList::ReleaseAsRecord() {
sk_sp<PaintRecord> record =
sk_make_sp<PaintOpBuffer>(std::move(paint_op_buffer_));
Reset();
return record;
}
} // namespace cc