| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "cc/resources/display_item_list.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/trace_event/trace_event.h" | |
| 10 #include "base/trace_event/trace_event_argument.h" | |
| 11 #include "cc/base/math_util.h" | |
| 12 #include "cc/debug/picture_debug_util.h" | |
| 13 #include "cc/debug/traced_picture.h" | |
| 14 #include "cc/debug/traced_value.h" | |
| 15 #include "cc/resources/largest_display_item.h" | |
| 16 #include "third_party/skia/include/core/SkCanvas.h" | |
| 17 #include "third_party/skia/include/core/SkDrawPictureCallback.h" | |
| 18 #include "third_party/skia/include/core/SkPictureRecorder.h" | |
| 19 #include "third_party/skia/include/utils/SkPictureUtils.h" | |
| 20 #include "ui/gfx/skia_util.h" | |
| 21 | |
| 22 namespace cc { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 bool PictureTracingEnabled() { | |
| 27 bool tracing_enabled; | |
| 28 TRACE_EVENT_CATEGORY_GROUP_ENABLED( | |
| 29 TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") "," | |
| 30 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"), | |
| 31 &tracing_enabled); | |
| 32 return tracing_enabled; | |
| 33 } | |
| 34 | |
| 35 const int kDefaultNumDisplayItemsToReserve = 100; | |
| 36 | |
| 37 } // namespace | |
| 38 | |
| 39 DisplayItemList::DisplayItemList(gfx::Rect layer_rect, | |
| 40 bool use_cached_picture, | |
| 41 bool retain_individual_display_items) | |
| 42 : items_(LargestDisplayItemSize(), kDefaultNumDisplayItemsToReserve), | |
| 43 use_cached_picture_(use_cached_picture), | |
| 44 retain_individual_display_items_(retain_individual_display_items), | |
| 45 layer_rect_(layer_rect), | |
| 46 is_suitable_for_gpu_rasterization_(true), | |
| 47 approximate_op_count_(0), | |
| 48 picture_memory_usage_(0) { | |
| 49 #if DCHECK_IS_ON() | |
| 50 needs_process_ = false; | |
| 51 #endif | |
| 52 if (use_cached_picture_) { | |
| 53 SkRTreeFactory factory; | |
| 54 recorder_.reset(new SkPictureRecorder()); | |
| 55 canvas_ = skia::SharePtr(recorder_->beginRecording( | |
| 56 layer_rect_.width(), layer_rect_.height(), &factory)); | |
| 57 canvas_->translate(-layer_rect_.x(), -layer_rect_.y()); | |
| 58 canvas_->clipRect(gfx::RectToSkRect(layer_rect_)); | |
| 59 } | |
| 60 } | |
| 61 | |
| 62 DisplayItemList::DisplayItemList(gfx::Rect layer_rect, bool use_cached_picture) | |
| 63 : DisplayItemList(layer_rect, | |
| 64 use_cached_picture, | |
| 65 !use_cached_picture || PictureTracingEnabled()) { | |
| 66 } | |
| 67 | |
| 68 scoped_refptr<DisplayItemList> DisplayItemList::Create( | |
| 69 gfx::Rect layer_rect, | |
| 70 bool use_cached_picture) { | |
| 71 return make_scoped_refptr( | |
| 72 new DisplayItemList(layer_rect, use_cached_picture)); | |
| 73 } | |
| 74 | |
| 75 DisplayItemList::~DisplayItemList() { | |
| 76 } | |
| 77 | |
| 78 void DisplayItemList::Raster(SkCanvas* canvas, | |
| 79 SkDrawPictureCallback* callback, | |
| 80 float contents_scale) const { | |
| 81 DCHECK(ProcessAppendedItemsCalled()); | |
| 82 if (!use_cached_picture_) { | |
| 83 canvas->save(); | |
| 84 canvas->scale(contents_scale, contents_scale); | |
| 85 for (auto* item : items_) | |
| 86 item->Raster(canvas, callback); | |
| 87 canvas->restore(); | |
| 88 } else { | |
| 89 DCHECK(picture_); | |
| 90 | |
| 91 canvas->save(); | |
| 92 canvas->scale(contents_scale, contents_scale); | |
| 93 canvas->translate(layer_rect_.x(), layer_rect_.y()); | |
| 94 if (callback) { | |
| 95 // If we have a callback, we need to call |draw()|, |drawPicture()| | |
| 96 // doesn't take a callback. This is used by |AnalysisCanvas| to early | |
| 97 // out. | |
| 98 picture_->playback(canvas, callback); | |
| 99 } else { | |
| 100 // Prefer to call |drawPicture()| on the canvas since it could place the | |
| 101 // entire picture on the canvas instead of parsing the skia operations. | |
| 102 canvas->drawPicture(picture_.get()); | |
| 103 } | |
| 104 canvas->restore(); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 void DisplayItemList::ProcessAppendedItemsOnTheFly() { | |
| 109 if (retain_individual_display_items_) | |
| 110 return; | |
| 111 if (items_.size() >= kDefaultNumDisplayItemsToReserve) { | |
| 112 ProcessAppendedItems(); | |
| 113 // This function exists to keep the |items_| from growing indefinitely if | |
| 114 // we're not going to store them anyway. So the items better be deleted | |
| 115 // after |items_| grows too large and we process it. | |
| 116 DCHECK(items_.empty()); | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 void DisplayItemList::ProcessAppendedItems() { | |
| 121 #if DCHECK_IS_ON() | |
| 122 needs_process_ = false; | |
| 123 #endif | |
| 124 for (DisplayItem* item : items_) { | |
| 125 is_suitable_for_gpu_rasterization_ &= | |
| 126 item->is_suitable_for_gpu_rasterization(); | |
| 127 approximate_op_count_ += item->approximate_op_count(); | |
| 128 | |
| 129 if (use_cached_picture_) { | |
| 130 DCHECK(canvas_); | |
| 131 item->Raster(canvas_.get(), NULL); | |
| 132 } | |
| 133 | |
| 134 if (retain_individual_display_items_) { | |
| 135 // Warning: this double-counts SkPicture data if use_cached_picture_ is | |
| 136 // also true. | |
| 137 picture_memory_usage_ += item->picture_memory_usage(); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 if (!retain_individual_display_items_) | |
| 142 items_.clear(); | |
| 143 } | |
| 144 | |
| 145 void DisplayItemList::CreateAndCacheSkPicture() { | |
| 146 DCHECK(ProcessAppendedItemsCalled()); | |
| 147 // Convert to an SkPicture for faster rasterization. | |
| 148 DCHECK(use_cached_picture_); | |
| 149 DCHECK(!picture_); | |
| 150 picture_ = skia::AdoptRef(recorder_->endRecordingAsPicture()); | |
| 151 DCHECK(picture_); | |
| 152 picture_memory_usage_ += SkPictureUtils::ApproximateBytesUsed(picture_.get()); | |
| 153 recorder_.reset(); | |
| 154 canvas_.clear(); | |
| 155 } | |
| 156 | |
| 157 bool DisplayItemList::IsSuitableForGpuRasterization() const { | |
| 158 DCHECK(ProcessAppendedItemsCalled()); | |
| 159 // This is more permissive than Picture's implementation, since none of the | |
| 160 // items might individually trigger a veto even though they collectively have | |
| 161 // enough "bad" operations that a corresponding Picture would get vetoed. | |
| 162 return is_suitable_for_gpu_rasterization_; | |
| 163 } | |
| 164 | |
| 165 int DisplayItemList::ApproximateOpCount() const { | |
| 166 DCHECK(ProcessAppendedItemsCalled()); | |
| 167 return approximate_op_count_; | |
| 168 } | |
| 169 | |
| 170 size_t DisplayItemList::PictureMemoryUsage() const { | |
| 171 DCHECK(ProcessAppendedItemsCalled()); | |
| 172 // We double-count in this case. Produce zero to avoid being misleading. | |
| 173 if (use_cached_picture_ && retain_individual_display_items_) | |
| 174 return 0; | |
| 175 | |
| 176 DCHECK_IMPLIES(use_cached_picture_, picture_); | |
| 177 return picture_memory_usage_; | |
| 178 } | |
| 179 | |
| 180 scoped_refptr<base::trace_event::ConvertableToTraceFormat> | |
| 181 DisplayItemList::AsValue() const { | |
| 182 DCHECK(ProcessAppendedItemsCalled()); | |
| 183 scoped_refptr<base::trace_event::TracedValue> state = | |
| 184 new base::trace_event::TracedValue(); | |
| 185 | |
| 186 state->SetInteger("length", items_.size()); | |
| 187 state->BeginArray("params.items"); | |
| 188 for (const DisplayItem* item : items_) { | |
| 189 item->AsValueInto(state.get()); | |
| 190 } | |
| 191 state->EndArray(); | |
| 192 state->SetValue("params.layer_rect", MathUtil::AsValue(layer_rect_)); | |
| 193 | |
| 194 SkPictureRecorder recorder; | |
| 195 SkCanvas* canvas = | |
| 196 recorder.beginRecording(layer_rect_.width(), layer_rect_.height()); | |
| 197 canvas->translate(-layer_rect_.x(), -layer_rect_.y()); | |
| 198 canvas->clipRect(gfx::RectToSkRect(layer_rect_)); | |
| 199 Raster(canvas, NULL, 1.f); | |
| 200 skia::RefPtr<SkPicture> picture = | |
| 201 skia::AdoptRef(recorder.endRecordingAsPicture()); | |
| 202 | |
| 203 std::string b64_picture; | |
| 204 PictureDebugUtil::SerializeAsBase64(picture.get(), &b64_picture); | |
| 205 state->SetString("skp64", b64_picture); | |
| 206 | |
| 207 return state; | |
| 208 } | |
| 209 | |
| 210 void DisplayItemList::EmitTraceSnapshot() const { | |
| 211 DCHECK(ProcessAppendedItemsCalled()); | |
| 212 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | |
| 213 TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") "," | |
| 214 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"), | |
| 215 "cc::DisplayItemList", this, AsValue()); | |
| 216 } | |
| 217 | |
| 218 void DisplayItemList::GatherPixelRefs(const gfx::Size& grid_cell_size) { | |
| 219 DCHECK(ProcessAppendedItemsCalled()); | |
| 220 // This should be only called once, and only after CreateAndCacheSkPicture. | |
| 221 DCHECK(picture_); | |
| 222 DCHECK(!pixel_refs_); | |
| 223 pixel_refs_ = make_scoped_ptr(new PixelRefMap(grid_cell_size)); | |
| 224 if (!picture_->willPlayBackBitmaps()) | |
| 225 return; | |
| 226 | |
| 227 pixel_refs_->GatherPixelRefsFromPicture(picture_.get()); | |
| 228 } | |
| 229 } // namespace cc | |
| OLD | NEW |