picture.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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 3// found in the LICENSE file. 4 5#include "cc/resources/picture.h" 6 7#include <algorithm> 8#include <limits> 9#include <set> 10 11#include "base/base64.h" 12#include "base/debug/trace_event.h" 13#include "base/values.h" 14#include "cc/base/math_util.h" 15#include "cc/base/util.h" 16#include "cc/debug/benchmark_instrumentation.h" 17#include "cc/debug/rendering_stats_instrumentation.h" 18#include "cc/debug/traced_picture.h" 19#include "cc/debug/traced_value.h" 20#include "cc/layers/content_layer_client.h" 21#include "skia/ext/lazy_pixel_ref_utils.h" 22#include "third_party/skia/include/core/SkCanvas.h" 23#include "third_party/skia/include/core/SkData.h" 24#include "third_party/skia/include/core/SkDrawFilter.h" 25#include "third_party/skia/include/core/SkPaint.h" 26#include "third_party/skia/include/core/SkStream.h" 27#include "third_party/skia/include/utils/SkPictureUtils.h" 28#include "ui/gfx/codec/jpeg_codec.h" 29#include "ui/gfx/codec/png_codec.h" 30#include "ui/gfx/rect_conversions.h" 31#include "ui/gfx/skia_util.h" 32 33namespace cc { 34 35namespace { 36 37SkData* EncodeBitmap(size_t* offset, const SkBitmap& bm) { 38 const int kJpegQuality = 80; 39 std::vector<unsigned char> data; 40 41 // If bitmap is opaque, encode as JPEG. 42 // Otherwise encode as PNG. 43 bool encoding_succeeded = false; 44 if (bm.isOpaque()) { 45 SkAutoLockPixels lock_bitmap(bm); 46 if (bm.empty()) 47 return NULL; 48 49 encoding_succeeded = gfx::JPEGCodec::Encode( 50 reinterpret_cast<unsigned char*>(bm.getAddr32(0, 0)), 51 gfx::JPEGCodec::FORMAT_SkBitmap, 52 bm.width(), 53 bm.height(), 54 bm.rowBytes(), 55 kJpegQuality, 56 &data); 57 } else { 58 encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data); 59 } 60 61 if (encoding_succeeded) { 62 *offset = 0; 63 return SkData::NewWithCopy(&data.front(), data.size()); 64 } 65 return NULL; 66} 67 68bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) { 69 const unsigned char* data = static_cast<const unsigned char *>(buffer); 70 71 // Try PNG first. 72 if (gfx::PNGCodec::Decode(data, size, bm)) 73 return true; 74 75 // Try JPEG. 76 scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size)); 77 if (decoded_jpeg) { 78 *bm = *decoded_jpeg; 79 return true; 80 } 81 return false; 82} 83 84} // namespace 85 86scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) { 87 return make_scoped_refptr(new Picture(layer_rect)); 88} 89 90Picture::Picture(gfx::Rect layer_rect) 91 : layer_rect_(layer_rect) { 92 // Instead of recording a trace event for object creation here, we wait for 93 // the picture to be recorded in Picture::Record. 94} 95 96scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) { 97 const base::DictionaryValue* value = NULL; 98 if (!raw_value->GetAsDictionary(&value)) 99 return NULL; 100 101 // Decode the picture from base64. 102 std::string encoded; 103 if (!value->GetString("skp64", &encoded)) 104 return NULL; 105 106 std::string decoded; 107 base::Base64Decode(encoded, &decoded); 108 SkMemoryStream stream(decoded.data(), decoded.size()); 109 110 const base::Value* layer_rect_value = NULL; 111 if (!value->Get("params.layer_rect", &layer_rect_value)) 112 return NULL; 113 114 gfx::Rect layer_rect; 115 if (!MathUtil::FromValue(layer_rect_value, &layer_rect)) 116 return NULL; 117 118 const base::Value* opaque_rect_value = NULL; 119 if (!value->Get("params.opaque_rect", &opaque_rect_value)) 120 return NULL; 121 122 gfx::Rect opaque_rect; 123 if (!MathUtil::FromValue(opaque_rect_value, &opaque_rect)) 124 return NULL; 125 126 // Read the picture. This creates an empty picture on failure. 127 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap); 128 if (skpicture == NULL) 129 return NULL; 130 131 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect)); 132} 133 134Picture::Picture(SkPicture* picture, 135 gfx::Rect layer_rect, 136 gfx::Rect opaque_rect) : 137 layer_rect_(layer_rect), 138 opaque_rect_(opaque_rect), 139 picture_(skia::AdoptRef(picture)) { 140} 141 142Picture::Picture(const skia::RefPtr<SkPicture>& picture, 143 gfx::Rect layer_rect, 144 gfx::Rect opaque_rect, 145 const PixelRefMap& pixel_refs) : 146 layer_rect_(layer_rect), 147 opaque_rect_(opaque_rect), 148 picture_(picture), 149 pixel_refs_(pixel_refs) { 150} 151 152Picture::~Picture() { 153 TRACE_EVENT_OBJECT_DELETED_WITH_ID( 154 TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this); 155} 156 157scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( 158 unsigned thread_index) const { 159 // SkPicture is not thread-safe to rasterize with, this returns a clone 160 // to rasterize with on a specific thread. 161 CHECK_GT(clones_.size(), thread_index); 162 return clones_[thread_index]; 163} 164 165void Picture::CloneForDrawing(int num_threads) { 166 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); 167 168 DCHECK(picture_); 169 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); 170 picture_->clone(&clones[0], num_threads); 171 172 clones_.clear(); 173 for (int i = 0; i < num_threads; i++) { 174 scoped_refptr<Picture> clone = make_scoped_refptr( 175 new Picture(skia::AdoptRef(new SkPicture(clones[i])), 176 layer_rect_, 177 opaque_rect_, 178 pixel_refs_)); 179 clones_.push_back(clone); 180 181 clone->EmitTraceSnapshot(); 182 } 183} 184 185void Picture::Record(ContentLayerClient* painter, 186 const SkTileGridPicture::TileGridInfo& tile_grid_info, 187 RenderingStatsInstrumentation* stats_instrumentation) { 188 TRACE_EVENT2(benchmark_instrumentation::kCategory, 189 benchmark_instrumentation::kPictureRecord, 190 benchmark_instrumentation::kWidth, layer_rect_.width(), 191 benchmark_instrumentation::kHeight, layer_rect_.height()); 192 193 DCHECK(!tile_grid_info.fTileInterval.isEmpty()); 194 picture_ = skia::AdoptRef(new SkTileGridPicture( 195 layer_rect_.width(), layer_rect_.height(), tile_grid_info)); 196 197 SkCanvas* canvas = picture_->beginRecording( 198 layer_rect_.width(), 199 layer_rect_.height(), 200 SkPicture::kUsePathBoundsForClip_RecordingFlag | 201 SkPicture::kOptimizeForClippedPlayback_RecordingFlag); 202 203 canvas->save(); 204 canvas->translate(SkFloatToScalar(-layer_rect_.x()), 205 SkFloatToScalar(-layer_rect_.y())); 206 207 SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(), 208 layer_rect_.y(), 209 layer_rect_.width(), 210 layer_rect_.height()); 211 canvas->clipRect(layer_skrect); 212 213 gfx::RectF opaque_layer_rect; 214 base::TimeTicks start_time = stats_instrumentation->StartRecording(); 215 216 painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect); 217 218 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); 219 stats_instrumentation->AddRecord(duration, 220 layer_rect_.width() * layer_rect_.height()); 221 222 canvas->restore(); 223 picture_->endRecording(); 224 225 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); 226 227 EmitTraceSnapshot(); 228} 229 230void Picture::GatherPixelRefs( 231 const SkTileGridPicture::TileGridInfo& tile_grid_info, 232 RenderingStatsInstrumentation* stats_instrumentation) { 233 TRACE_EVENT2("cc", "Picture::GatherPixelRefs", 234 "width", layer_rect_.width(), 235 "height", layer_rect_.height()); 236 237 DCHECK(picture_); 238 cell_size_ = gfx::Size( 239 tile_grid_info.fTileInterval.width() + 240 2 * tile_grid_info.fMargin.width(), 241 tile_grid_info.fTileInterval.height() + 242 2 * tile_grid_info.fMargin.height()); 243 DCHECK_GT(cell_size_.width(), 0); 244 DCHECK_GT(cell_size_.height(), 0); 245 246 int min_x = std::numeric_limits<int>::max(); 247 int min_y = std::numeric_limits<int>::max(); 248 int max_x = 0; 249 int max_y = 0; 250 251 base::TimeTicks start_time = stats_instrumentation->StartRecording(); 252 253 skia::LazyPixelRefList pixel_refs; 254 skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs); 255 for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin(); 256 it != pixel_refs.end(); 257 ++it) { 258 gfx::Point min( 259 RoundDown(static_cast<int>(it->pixel_ref_rect.x()), 260 cell_size_.width()), 261 RoundDown(static_cast<int>(it->pixel_ref_rect.y()), 262 cell_size_.height())); 263 gfx::Point max( 264 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())), 265 cell_size_.width()), 266 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())), 267 cell_size_.height())); 268 269 for (int y = min.y(); y <= max.y(); y += cell_size_.height()) { 270 for (int x = min.x(); x <= max.x(); x += cell_size_.width()) { 271 PixelRefMapKey key(x, y); 272 pixel_refs_[key].push_back(it->lazy_pixel_ref); 273 } 274 } 275 276 min_x = std::min(min_x, min.x()); 277 min_y = std::min(min_y, min.y()); 278 max_x = std::max(max_x, max.x()); 279 max_y = std::max(max_y, max.y()); 280 } 281 282 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); 283 stats_instrumentation->AddImageGathering(duration); 284 285 min_pixel_cell_ = gfx::Point(min_x, min_y); 286 max_pixel_cell_ = gfx::Point(max_x, max_y); 287} 288 289void Picture::Raster( 290 SkCanvas* canvas, 291 SkDrawPictureCallback* callback, 292 gfx::Rect content_rect, 293 float contents_scale) { 294 TRACE_EVENT_BEGIN1(benchmark_instrumentation::kCategory, 295 benchmark_instrumentation::kPictureRaster, 296 "data", 297 AsTraceableRasterData(content_rect, contents_scale)); 298 299 DCHECK(picture_); 300 301 canvas->save(); 302 canvas->clipRect(gfx::RectToSkRect(content_rect)); 303 canvas->scale(contents_scale, contents_scale); 304 canvas->translate(layer_rect_.x(), layer_rect_.y()); 305 picture_->draw(canvas, callback); 306 SkIRect bounds; 307 canvas->getClipDeviceBounds(&bounds); 308 canvas->restore(); 309 TRACE_EVENT_END1(benchmark_instrumentation::kCategory, 310 benchmark_instrumentation::kPictureRaster, 311 benchmark_instrumentation::kNumPixelsRasterized, 312 bounds.width() * bounds.height()); 313} 314 315void Picture::Replay(SkCanvas* canvas) { 316 TRACE_EVENT_BEGIN0("cc", "Picture::Replay"); 317 DCHECK(picture_); 318 319 picture_->draw(canvas); 320 SkIRect bounds; 321 canvas->getClipDeviceBounds(&bounds); 322 TRACE_EVENT_END1("cc", "Picture::Replay", 323 "num_pixels_replayed", bounds.width() * bounds.height()); 324} 325 326scoped_ptr<base::Value> Picture::AsValue() const { 327 SkDynamicMemoryWStream stream; 328 329 // Serialize the picture. 330 picture_->serialize(&stream, &EncodeBitmap); 331 332 // Encode the picture as base64. 333 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); 334 res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release()); 335 res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release()); 336 337 size_t serialized_size = stream.bytesWritten(); 338 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); 339 stream.copyTo(serialized_picture.get()); 340 std::string b64_picture; 341 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), 342 &b64_picture); 343 res->SetString("skp64", b64_picture); 344 return res.PassAs<base::Value>(); 345} 346 347void Picture::EmitTraceSnapshot() { 348 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"), 349 "cc::Picture", this, TracedPicture::AsTraceablePicture(this)); 350} 351 352base::LazyInstance<Picture::PixelRefs> 353 Picture::PixelRefIterator::empty_pixel_refs_; 354 355Picture::PixelRefIterator::PixelRefIterator() 356 : picture_(NULL), 357 current_pixel_refs_(empty_pixel_refs_.Pointer()), 358 current_index_(0), 359 min_point_(-1, -1), 360 max_point_(-1, -1), 361 current_x_(0), 362 current_y_(0) { 363} 364 365Picture::PixelRefIterator::PixelRefIterator( 366 gfx::Rect query_rect, 367 const Picture* picture) 368 : picture_(picture), 369 current_pixel_refs_(empty_pixel_refs_.Pointer()), 370 current_index_(0) { 371 gfx::Rect layer_rect = picture->layer_rect_; 372 gfx::Size cell_size = picture->cell_size_; 373 374 // Early out if the query rect doesn't intersect this picture 375 if (!query_rect.Intersects(layer_rect)) { 376 min_point_ = gfx::Point(0, 0); 377 max_point_ = gfx::Point(0, 0); 378 current_x_ = 1; 379 current_y_ = 1; 380 return; 381 } 382 383 // First, subtract the layer origin as cells are stored in layer space. 384 query_rect.Offset(-layer_rect.OffsetFromOrigin()); 385 386 // We have to find a cell_size aligned point that corresponds to 387 // query_rect. Point is a multiple of cell_size. 388 min_point_ = gfx::Point( 389 RoundDown(query_rect.x(), cell_size.width()), 390 RoundDown(query_rect.y(), cell_size.height())); 391 max_point_ = gfx::Point( 392 RoundDown(query_rect.right() - 1, cell_size.width()), 393 RoundDown(query_rect.bottom() - 1, cell_size.height())); 394 395 // Limit the points to known pixel ref boundaries. 396 min_point_ = gfx::Point( 397 std::max(min_point_.x(), picture->min_pixel_cell_.x()), 398 std::max(min_point_.y(), picture->min_pixel_cell_.y())); 399 max_point_ = gfx::Point( 400 std::min(max_point_.x(), picture->max_pixel_cell_.x()), 401 std::min(max_point_.y(), picture->max_pixel_cell_.y())); 402 403 // Make the current x be cell_size.width() less than min point, so that 404 // the first increment will point at min_point_. 405 current_x_ = min_point_.x() - cell_size.width(); 406 current_y_ = min_point_.y(); 407 if (current_y_ <= max_point_.y()) 408 ++(*this); 409} 410 411Picture::PixelRefIterator::~PixelRefIterator() { 412} 413 414Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() { 415 ++current_index_; 416 // If we're not at the end of the list, then we have the next item. 417 if (current_index_ < current_pixel_refs_->size()) 418 return *this; 419 420 DCHECK(current_y_ <= max_point_.y()); 421 while (true) { 422 gfx::Size cell_size = picture_->cell_size_; 423 424 // Advance the current grid cell. 425 current_x_ += cell_size.width(); 426 if (current_x_ > max_point_.x()) { 427 current_y_ += cell_size.height(); 428 current_x_ = min_point_.x(); 429 if (current_y_ > max_point_.y()) { 430 current_pixel_refs_ = empty_pixel_refs_.Pointer(); 431 current_index_ = 0; 432 break; 433 } 434 } 435 436 // If there are no pixel refs at this grid cell, keep incrementing. 437 PixelRefMapKey key(current_x_, current_y_); 438 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key); 439 if (iter == picture_->pixel_refs_.end()) 440 continue; 441 442 // We found a non-empty list: store it and get the first pixel ref. 443 current_pixel_refs_ = &iter->second; 444 current_index_ = 0; 445 break; 446 } 447 return *this; 448} 449 450scoped_ptr<base::debug::ConvertableToTraceFormat> 451 Picture::AsTraceableRasterData(gfx::Rect rect, float scale) { 452 scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue()); 453 raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release()); 454 raster_data->SetDouble("scale", scale); 455 raster_data->SetDouble("rect_x", rect.x()); 456 raster_data->SetDouble("rect_y", rect.y()); 457 raster_data->SetDouble("rect_width", rect.width()); 458 raster_data->SetDouble("rect_height", rect.height()); 459 return TracedValue::FromValue(raster_data.release()); 460} 461 462} // namespace cc 463