Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Side by Side Diff: cc/resources/picture.cc

Issue 14230007: cc: Do GatherPixelRefs from skia at record time (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: unittests + enne's review Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/resources/picture.h" 5 #include "cc/resources/picture.h"
6 6
7 #include <algorithm>
8 #include <limits>
9 #include <set>
10
7 #include "base/base64.h" 11 #include "base/base64.h"
8 #include "base/debug/trace_event.h" 12 #include "base/debug/trace_event.h"
9 #include "cc/debug/rendering_stats.h" 13 #include "cc/debug/rendering_stats.h"
10 #include "cc/layers/content_layer_client.h" 14 #include "cc/layers/content_layer_client.h"
11 #include "skia/ext/analysis_canvas.h" 15 #include "skia/ext/analysis_canvas.h"
12 #include "third_party/skia/include/core/SkCanvas.h" 16 #include "third_party/skia/include/core/SkCanvas.h"
13 #include "third_party/skia/include/core/SkData.h" 17 #include "third_party/skia/include/core/SkData.h"
14 #include "third_party/skia/include/core/SkDrawFilter.h" 18 #include "third_party/skia/include/core/SkDrawFilter.h"
15 #include "third_party/skia/include/core/SkPaint.h" 19 #include "third_party/skia/include/core/SkPaint.h"
16 #include "third_party/skia/include/core/SkStream.h" 20 #include "third_party/skia/include/core/SkStream.h"
17 #include "third_party/skia/include/utils/SkPictureUtils.h" 21 #include "third_party/skia/include/utils/SkPictureUtils.h"
18 #include "ui/gfx/rect_conversions.h" 22 #include "ui/gfx/rect_conversions.h"
19 #include "ui/gfx/skia_util.h" 23 #include "ui/gfx/skia_util.h"
20 24
21 namespace { 25 namespace {
22 // URI label for a lazily decoded SkPixelRef. 26 // URI label for a lazily decoded SkPixelRef.
23 const char kLabelLazyDecoded[] = "lazy"; 27 const char kLabelLazyDecoded[] = "lazy";
28
24 // Version ID; to be used in serialization. 29 // Version ID; to be used in serialization.
25 const int kPictureVersion = 1; 30 const int kPictureVersion = 1;
31
26 // Minimum size of a decoded stream that we need. 32 // Minimum size of a decoded stream that we need.
27 // 4 bytes for version, 4 * 4 for each of the 2 rects. 33 // 4 bytes for version, 4 * 4 for each of the 2 rects.
28 const unsigned int kMinPictureSizeBytes = 36; 34 const unsigned int kMinPictureSizeBytes = 36;
29 35
36 // Size of each of the grid cells for storing lazy pixel refs.
37 const int kRegionWidth = 512;
38 const int kRegionHeight = 512;
reveman 2013/04/22 19:56:06 Can we avoid these constants and use SkTileGridPic
vmpstr 2013/04/22 22:38:16 Done.
39
30 class DisableLCDTextFilter : public SkDrawFilter { 40 class DisableLCDTextFilter : public SkDrawFilter {
31 public: 41 public:
32 // SkDrawFilter interface. 42 // SkDrawFilter interface.
33 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE { 43 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE {
34 if (type != SkDrawFilter::kText_Type) 44 if (type != SkDrawFilter::kText_Type)
35 return true; 45 return true;
36 46
37 paint->setLCDRenderText(false); 47 paint->setLCDRenderText(false);
38 return true; 48 return true;
39 } 49 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 opaque_rect_y, 104 opaque_rect_y,
95 opaque_rect_width, 105 opaque_rect_width,
96 opaque_rect_height); 106 opaque_rect_height);
97 107
98 // Read the picture. This creates an empty picture on failure. 108 // Read the picture. This creates an empty picture on failure.
99 picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL)); 109 picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL));
100 } 110 }
101 111
102 Picture::Picture(const skia::RefPtr<SkPicture>& picture, 112 Picture::Picture(const skia::RefPtr<SkPicture>& picture,
103 gfx::Rect layer_rect, 113 gfx::Rect layer_rect,
104 gfx::Rect opaque_rect) : 114 gfx::Rect opaque_rect,
115 const PixelRefsMap& lazy_pixel_refs) :
enne (OOO) 2013/04/22 19:10:56 PixelRefsMap => PixelRefMap?
vmpstr 2013/04/22 22:38:16 Done.
105 layer_rect_(layer_rect), 116 layer_rect_(layer_rect),
106 opaque_rect_(opaque_rect), 117 opaque_rect_(opaque_rect),
107 picture_(picture) { 118 picture_(picture),
119 lazy_pixel_refs_(lazy_pixel_refs) {
108 } 120 }
109 121
110 Picture::~Picture() { 122 Picture::~Picture() {
111 } 123 }
112 124
113 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( 125 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread(
114 unsigned thread_index) const { 126 unsigned thread_index) const {
115 // SkPicture is not thread-safe to rasterize with, this returns a clone 127 // SkPicture is not thread-safe to rasterize with, this returns a clone
116 // to rasterize with on a specific thread. 128 // to rasterize with on a specific thread.
117 CHECK_GT(clones_.size(), thread_index); 129 CHECK_GT(clones_.size(), thread_index);
118 return clones_[thread_index]; 130 return clones_[thread_index];
119 } 131 }
120 132
121 void Picture::CloneForDrawing(int num_threads) { 133 void Picture::CloneForDrawing(int num_threads) {
122 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); 134 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
123 135
124 DCHECK(picture_); 136 DCHECK(picture_);
125 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); 137 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]);
126 picture_->clone(&clones[0], num_threads); 138 picture_->clone(&clones[0], num_threads);
127 139
128 clones_.clear(); 140 clones_.clear();
129 for (int i = 0; i < num_threads; i++) { 141 for (int i = 0; i < num_threads; i++) {
130 scoped_refptr<Picture> clone = make_scoped_refptr( 142 scoped_refptr<Picture> clone = make_scoped_refptr(
131 new Picture(skia::AdoptRef(new SkPicture(clones[i])), 143 new Picture(skia::AdoptRef(new SkPicture(clones[i])),
132 layer_rect_, 144 layer_rect_,
133 opaque_rect_)); 145 opaque_rect_,
146 lazy_pixel_refs_));
134 clones_.push_back(clone); 147 clones_.push_back(clone);
135 } 148 }
136 } 149 }
137 150
138 void Picture::Record(ContentLayerClient* painter, 151 void Picture::Record(ContentLayerClient* painter,
139 RenderingStats* stats, 152 RenderingStats* stats,
140 const SkTileGridPicture::TileGridInfo& tile_grid_info) { 153 const SkTileGridPicture::TileGridInfo& tile_grid_info) {
141 TRACE_EVENT2("cc", "Picture::Record", 154 TRACE_EVENT2("cc", "Picture::Record",
142 "width", layer_rect_.width(), "height", layer_rect_.height()); 155 "width", layer_rect_.width(), "height", layer_rect_.height());
143 156
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 if (stats) { 188 if (stats) {
176 stats->total_paint_time += base::TimeTicks::Now() - begin_paint_time; 189 stats->total_paint_time += base::TimeTicks::Now() - begin_paint_time;
177 stats->total_pixels_painted += 190 stats->total_pixels_painted +=
178 layer_rect_.width() * layer_rect_.height(); 191 layer_rect_.width() * layer_rect_.height();
179 } 192 }
180 193
181 canvas->restore(); 194 canvas->restore();
182 picture_->endRecording(); 195 picture_->endRecording();
183 196
184 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); 197 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
198
199 GatherAllPixelRefs();
185 } 200 }
186 201
187 void Picture::Raster( 202 void Picture::Raster(
188 SkCanvas* canvas, 203 SkCanvas* canvas,
189 gfx::Rect content_rect, 204 gfx::Rect content_rect,
190 float contents_scale, 205 float contents_scale,
191 bool enable_lcd_text) { 206 bool enable_lcd_text) {
192 TRACE_EVENT2("cc", "Picture::Raster", 207 TRACE_EVENT2("cc", "Picture::Raster",
193 "layer width", layer_rect_.width(), 208 "layer width", layer_rect_.width(),
194 "layer height", layer_rect_.height()); 209 "layer height", layer_rect_.height());
195 DCHECK(picture_); 210 DCHECK(picture_);
196 211
197 DisableLCDTextFilter disable_lcd_text_filter; 212 DisableLCDTextFilter disable_lcd_text_filter;
198 213
199 canvas->save(); 214 canvas->save();
200 canvas->clipRect(gfx::RectToSkRect(content_rect)); 215 canvas->clipRect(gfx::RectToSkRect(content_rect));
201 canvas->scale(contents_scale, contents_scale); 216 canvas->scale(contents_scale, contents_scale);
202 canvas->translate(layer_rect_.x(), layer_rect_.y()); 217 canvas->translate(layer_rect_.x(), layer_rect_.y());
203 // Pictures by default have LCD text enabled. 218 // Pictures by default have LCD text enabled.
204 if (!enable_lcd_text) 219 if (!enable_lcd_text)
205 canvas->setDrawFilter(&disable_lcd_text_filter); 220 canvas->setDrawFilter(&disable_lcd_text_filter);
206 canvas->drawPicture(*picture_); 221 canvas->drawPicture(*picture_);
207 canvas->restore(); 222 canvas->restore();
208 } 223 }
209 224
210 void Picture::GatherPixelRefs(const gfx::Rect& layer_rect, 225 void Picture::GatherPixelRefsFromSkia(
211 std::list<skia::LazyPixelRef*>& pixel_ref_list) { 226 const gfx::Rect& layer_rect,
227 std::list<skia::LazyPixelRef*>& pixel_ref_list) {
212 DCHECK(picture_); 228 DCHECK(picture_);
213 SkData* pixel_refs = SkPictureUtils::GatherPixelRefs( 229 SkData* pixel_refs = SkPictureUtils::GatherPixelRefs(
214 picture_.get(), SkRect::MakeXYWH(layer_rect.x(), 230 picture_.get(), SkRect::MakeXYWH(layer_rect.x() - layer_rect_.x(),
215 layer_rect.y(), 231 layer_rect.y() - layer_rect_.y(),
enne (OOO) 2013/04/22 19:10:56 I think you mean 0? ;) Is the reason for this bec
vmpstr 2013/04/22 22:38:16 No, it's actually a different rect... I renamed th
216 layer_rect.width(), 232 layer_rect.width(),
217 layer_rect.height())); 233 layer_rect.height()));
218 if (!pixel_refs) 234 if (!pixel_refs)
219 return; 235 return;
220 236
221 void* data = const_cast<void*>(pixel_refs->data()); 237 void* data = const_cast<void*>(pixel_refs->data());
222 if (!data) { 238 if (!data) {
223 pixel_refs->unref(); 239 pixel_refs->unref();
224 return; 240 return;
225 } 241 }
(...skipping 29 matching lines...) Expand all
255 picture_->serialize(&stream); 271 picture_->serialize(&stream);
256 272
257 // Encode the picture as base64. 273 // Encode the picture as base64.
258 size_t serialized_size = stream.bytesWritten(); 274 size_t serialized_size = stream.bytesWritten();
259 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); 275 scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
260 stream.copyTo(serialized_picture.get()); 276 stream.copyTo(serialized_picture.get());
261 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), 277 base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
262 output); 278 output);
263 } 279 }
264 280
281 void Picture::GatherAllPixelRefs() {
282 int min_x = std::numeric_limits<int>::max();
283 int min_y = std::numeric_limits<int>::max();
284 int max_x = 0;
285 int max_y = 0;
286
287 // Capture pixel refs for this picture in a grid
288 // with kRegionWidth by kRegionHeight cells.
289 for (int y = layer_rect_.y(); y < layer_rect_.bottom(); y += kRegionHeight) {
290 for (int x = layer_rect_.x(); x < layer_rect_.right(); x += kRegionWidth) {
291 gfx::Size extent(std::min(kRegionWidth, layer_rect_.right() - x),
292 std::min(kRegionHeight, layer_rect_.bottom() - y));
293 gfx::Rect rect(x, y, extent.width(), extent.height());
294
295 std::list<skia::LazyPixelRef*> lazy_pixel_refs;
296 GatherPixelRefsFromSkia(rect, lazy_pixel_refs);
enne (OOO) 2013/04/22 19:10:56 If only Skia could just give us bounding rectangle
vmpstr 2013/04/22 22:38:16 Yep. Maybe they will in the future :D
297
298 // Only capture non-empty cells.
299 if (!lazy_pixel_refs.empty()) {
300 lazy_pixel_refs_[std::make_pair(x, y)].swap(lazy_pixel_refs);
301 min_x = std::min(min_x, x);
302 min_y = std::min(min_y, y);
303 max_x = std::max(max_x, x);
304 max_y = std::max(max_y, y);
305 }
306 }
307 }
308
309 min_lazy_pixel_cell_ = gfx::Point(min_x, min_y);
310 max_lazy_pixel_cell_ = gfx::Point(max_x, max_y);
311 }
312
313 Picture::LazyPixelRefIterator::LazyPixelRefIterator()
enne (OOO) 2013/04/22 19:10:56 Ok, this makes sense. Thanks for the default ctor
314 : picture_(0),
reveman 2013/04/22 19:56:06 nit: indent 4 spaces
vmpstr 2013/04/22 22:38:16 Done.
315 current_pixel_ref_(0),
316 min_point_(-1, -1),
317 max_point_(-1, -1),
318 current_x_(0),
319 current_y_(0) {
320 }
321
322 Picture::LazyPixelRefIterator::LazyPixelRefIterator(
323 gfx::Rect rect,
324 const Picture* picture)
325 : picture_(picture),
326 current_pixel_ref_(NULL) {
327 gfx::Rect layer_rect = picture->layer_rect_;
328
329 // We have to find a kRegionWidth/kRegionHeight aligned point that
330 // corresponds to the given rect. First, subtract the layer origin,
331 // then ensure the point is a multiple of kRegionWidth/kRegionHeight,
332 // and finally, add the layer origin back.
333 min_point_ = gfx::Point(
334 ((rect.x() - layer_rect.x()) / kRegionWidth) * kRegionWidth
335 + layer_rect.x(),
336 ((rect.y() - layer_rect.y()) / kRegionHeight) * kRegionHeight
337 + layer_rect.y());
338 max_point_ = gfx::Point(
339 ((rect.right() - layer_rect.x()) / kRegionWidth) * kRegionWidth
340 + layer_rect.x(),
341 ((rect.bottom() - layer_rect.y()) / kRegionHeight) * kRegionHeight
342 + layer_rect.y());
343
344 // Limit the points to knows pixel ref boundaries.
345 min_point_ = gfx::Point(
346 std::max(min_point_.x(), picture->min_lazy_pixel_cell_.x()),
enne (OOO) 2013/04/22 19:10:56 I think this is wrong. lazy_pixel_cell is in laye
vmpstr 2013/04/22 22:38:16 This is actually in layer space, since I add layer
347 std::max(min_point_.y(), picture->min_lazy_pixel_cell_.y()));
348 max_point_ = gfx::Point(
349 std::min(max_point_.x(), picture->max_lazy_pixel_cell_.x()),
350 std::min(max_point_.y(), picture->max_lazy_pixel_cell_.y()));
351
352 // Make the current x be kRegionWidth less than min point, so that
353 // the first increment will point at min_point_.
354 current_x_ = min_point_.x() - kRegionWidth;
355 current_y_ = min_point_.y();
356 ++(*this);
357 }
358
359 Picture::LazyPixelRefIterator::~LazyPixelRefIterator() {
360 }
361
362 Picture::LazyPixelRefIterator& Picture::LazyPixelRefIterator::operator++() {
363 // If we're not at the end of the list, then just get the next item.
364 if (!current_list_.empty()) {
365 current_pixel_ref_ = current_list_.front();
366 current_list_.pop_front();
367 return *this;
368 }
369
370 // If we already passed the max y, do nothing.
371 if (current_y_ > max_point_.y())
372 return *this;
373
374 while (true) {
375 // Advance the current grid cell.
376 current_x_ += kRegionWidth;
377 if (current_x_ > max_point_.x()) {
378 current_y_ += kRegionHeight;
379 current_x_ = min_point_.x();
380 if (current_y_ > max_point_.y()) {
381 current_pixel_ref_ = NULL;
382 break;
383 }
384 }
385
386 // If there are no pixel refs at this grid cell, keep incrementing.
387 PixelRefsMap::const_iterator iter =
388 picture_->lazy_pixel_refs_.find(std::make_pair(current_x_, current_y_));
389 if (iter == picture_->lazy_pixel_refs_.end() || iter->second.empty())
reveman 2013/04/22 19:56:06 can "iter->second.empty()" ever be true?
vmpstr 2013/04/22 22:38:16 Nope, I removed it.
390 continue;
391
392 // We found a non-empty list: store it and get the first pixel ref.
393 current_list_ = iter->second;
reveman 2013/04/22 19:56:06 Can we avoid copying this list while iterating? lo
vmpstr 2013/04/22 22:38:16 Done.
394 current_pixel_ref_ = current_list_.front();
395 current_list_.pop_front();
396 break;
397 }
398 return *this;
399 }
400
265 } // namespace cc 401 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698