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 33 namespace cc { 34 35 namespace { 36 37 SkData* 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 68 bool 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 86 scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) { 87 return make_scoped_refptr(new Picture(layer_rect)); 88 } 89 90 Picture::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 96 scoped_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 134 Picture::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 142 Picture::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 152 Picture::~Picture() { 153 TRACE_EVENT_OBJECT_DELETED_WITH_ID( 154 TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this); 155 } 156 157 scoped_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 165 void 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 185 void Picture::Record(ContentLayerClient* painter, 186 const SkTileGridPicture::TileGridInfo& tile_grid_info, 187 RenderingStatsInstrumentation* stats_instrumentation) { 188 TRACE_EVENT1(benchmark_instrumentation::kCategory, 189 benchmark_instrumentation::kPictureRecord, 190 benchmark_instrumentation::kData, AsTraceableRecordData()); 191 192 DCHECK(!tile_grid_info.fTileInterval.isEmpty()); 193 picture_ = skia::AdoptRef(new SkTileGridPicture( 194 layer_rect_.width(), layer_rect_.height(), tile_grid_info)); 195 196 SkCanvas* canvas = picture_->beginRecording( 197 layer_rect_.width(), 198 layer_rect_.height(), 199 SkPicture::kUsePathBoundsForClip_RecordingFlag | 200 SkPicture::kOptimizeForClippedPlayback_RecordingFlag); 201 202 canvas->save(); 203 canvas->translate(SkFloatToScalar(-layer_rect_.x()), 204 SkFloatToScalar(-layer_rect_.y())); 205 206 SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(), 207 layer_rect_.y(), 208 layer_rect_.width(), 209 layer_rect_.height()); 210 canvas->clipRect(layer_skrect); 211 212 gfx::RectF opaque_layer_rect; 213 base::TimeTicks start_time = stats_instrumentation->StartRecording(); 214 215 painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect); 216 217 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); 218 stats_instrumentation->AddRecord(duration, 219 layer_rect_.width() * layer_rect_.height()); 220 221 canvas->restore(); 222 picture_->endRecording(); 223 224 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); 225 226 EmitTraceSnapshot(); 227 } 228 229 void Picture::GatherPixelRefs( 230 const SkTileGridPicture::TileGridInfo& tile_grid_info, 231 RenderingStatsInstrumentation* stats_instrumentation) { 232 TRACE_EVENT2("cc", "Picture::GatherPixelRefs", 233 "width", layer_rect_.width(), 234 "height", layer_rect_.height()); 235 236 DCHECK(picture_); 237 cell_size_ = gfx::Size( 238 tile_grid_info.fTileInterval.width() + 239 2 * tile_grid_info.fMargin.width(), 240 tile_grid_info.fTileInterval.height() + 241 2 * tile_grid_info.fMargin.height()); 242 DCHECK_GT(cell_size_.width(), 0); 243 DCHECK_GT(cell_size_.height(), 0); 244 245 int min_x = std::numeric_limits<int>::max(); 246 int min_y = std::numeric_limits<int>::max(); 247 int max_x = 0; 248 int max_y = 0; 249 250 base::TimeTicks start_time = stats_instrumentation->StartRecording(); 251 252 skia::LazyPixelRefList pixel_refs; 253 skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs); 254 for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin(); 255 it != pixel_refs.end(); 256 ++it) { 257 gfx::Point min( 258 RoundDown(static_cast<int>(it->pixel_ref_rect.x()), 259 cell_size_.width()), 260 RoundDown(static_cast<int>(it->pixel_ref_rect.y()), 261 cell_size_.height())); 262 gfx::Point max( 263 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())), 264 cell_size_.width()), 265 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())), 266 cell_size_.height())); 267 268 for (int y = min.y(); y <= max.y(); y += cell_size_.height()) { 269 for (int x = min.x(); x <= max.x(); x += cell_size_.width()) { 270 PixelRefMapKey key(x, y); 271 pixel_refs_[key].push_back(it->lazy_pixel_ref); 272 } 273 } 274 275 min_x = std::min(min_x, min.x()); 276 min_y = std::min(min_y, min.y()); 277 max_x = std::max(max_x, max.x()); 278 max_y = std::max(max_y, max.y()); 279 } 280 281 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); 282 stats_instrumentation->AddImageGathering(duration); 283 284 min_pixel_cell_ = gfx::Point(min_x, min_y); 285 max_pixel_cell_ = gfx::Point(max_x, max_y); 286 } 287 288 void Picture::Raster( 289 SkCanvas* canvas, 290 SkDrawPictureCallback* callback, 291 gfx::Rect content_rect, 292 float contents_scale) { 293 TRACE_EVENT_BEGIN1(benchmark_instrumentation::kCategory, 294 benchmark_instrumentation::kPictureRaster, 295 "data", 296 AsTraceableRasterData(content_rect, contents_scale)); 297 298 DCHECK(picture_); 299 300 canvas->save(); 301 canvas->clipRect(gfx::RectToSkRect(content_rect)); 302 canvas->scale(contents_scale, contents_scale); 303 canvas->translate(layer_rect_.x(), layer_rect_.y()); 304 picture_->draw(canvas, callback); 305 SkIRect bounds; 306 canvas->getClipDeviceBounds(&bounds); 307 canvas->restore(); 308 TRACE_EVENT_END1(benchmark_instrumentation::kCategory, 309 benchmark_instrumentation::kPictureRaster, 310 benchmark_instrumentation::kNumPixelsRasterized, 311 bounds.width() * bounds.height()); 312 } 313 314 void Picture::Replay(SkCanvas* canvas) { 315 TRACE_EVENT_BEGIN0("cc", "Picture::Replay"); 316 DCHECK(picture_); 317 318 picture_->draw(canvas); 319 SkIRect bounds; 320 canvas->getClipDeviceBounds(&bounds); 321 TRACE_EVENT_END1("cc", "Picture::Replay", 322 "num_pixels_replayed", bounds.width() * bounds.height()); 323 } 324 325 scoped_ptr<base::Value> Picture::AsValue() const { 326 SkDynamicMemoryWStream stream; 327 328 // Serialize the picture. 329 picture_->serialize(&stream, &EncodeBitmap); 330 331 // Encode the picture as base64. 332 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); 333 res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release()); 334 res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release()); 335 336 size_t serialized_size = stream.bytesWritten(); 337 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); 338 stream.copyTo(serialized_picture.get()); 339 std::string b64_picture; 340 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), 341 &b64_picture); 342 res->SetString("skp64", b64_picture); 343 return res.PassAs<base::Value>(); 344 } 345 346 void Picture::EmitTraceSnapshot() { 347 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"), 348 "cc::Picture", this, TracedPicture::AsTraceablePicture(this)); 349 } 350 351 base::LazyInstance<Picture::PixelRefs> 352 Picture::PixelRefIterator::empty_pixel_refs_; 353 354 Picture::PixelRefIterator::PixelRefIterator() 355 : picture_(NULL), 356 current_pixel_refs_(empty_pixel_refs_.Pointer()), 357 current_index_(0), 358 min_point_(-1, -1), 359 max_point_(-1, -1), 360 current_x_(0), 361 current_y_(0) { 362 } 363 364 Picture::PixelRefIterator::PixelRefIterator( 365 gfx::Rect query_rect, 366 const Picture* picture) 367 : picture_(picture), 368 current_pixel_refs_(empty_pixel_refs_.Pointer()), 369 current_index_(0) { 370 gfx::Rect layer_rect = picture->layer_rect_; 371 gfx::Size cell_size = picture->cell_size_; 372 373 // Early out if the query rect doesn't intersect this picture 374 if (!query_rect.Intersects(layer_rect)) { 375 min_point_ = gfx::Point(0, 0); 376 max_point_ = gfx::Point(0, 0); 377 current_x_ = 1; 378 current_y_ = 1; 379 return; 380 } 381 382 // First, subtract the layer origin as cells are stored in layer space. 383 query_rect.Offset(-layer_rect.OffsetFromOrigin()); 384 385 // We have to find a cell_size aligned point that corresponds to 386 // query_rect. Point is a multiple of cell_size. 387 min_point_ = gfx::Point( 388 RoundDown(query_rect.x(), cell_size.width()), 389 RoundDown(query_rect.y(), cell_size.height())); 390 max_point_ = gfx::Point( 391 RoundDown(query_rect.right() - 1, cell_size.width()), 392 RoundDown(query_rect.bottom() - 1, cell_size.height())); 393 394 // Limit the points to known pixel ref boundaries. 395 min_point_ = gfx::Point( 396 std::max(min_point_.x(), picture->min_pixel_cell_.x()), 397 std::max(min_point_.y(), picture->min_pixel_cell_.y())); 398 max_point_ = gfx::Point( 399 std::min(max_point_.x(), picture->max_pixel_cell_.x()), 400 std::min(max_point_.y(), picture->max_pixel_cell_.y())); 401 402 // Make the current x be cell_size.width() less than min point, so that 403 // the first increment will point at min_point_. 404 current_x_ = min_point_.x() - cell_size.width(); 405 current_y_ = min_point_.y(); 406 if (current_y_ <= max_point_.y()) 407 ++(*this); 408 } 409 410 Picture::PixelRefIterator::~PixelRefIterator() { 411 } 412 413 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() { 414 ++current_index_; 415 // If we're not at the end of the list, then we have the next item. 416 if (current_index_ < current_pixel_refs_->size()) 417 return *this; 418 419 DCHECK(current_y_ <= max_point_.y()); 420 while (true) { 421 gfx::Size cell_size = picture_->cell_size_; 422 423 // Advance the current grid cell. 424 current_x_ += cell_size.width(); 425 if (current_x_ > max_point_.x()) { 426 current_y_ += cell_size.height(); 427 current_x_ = min_point_.x(); 428 if (current_y_ > max_point_.y()) { 429 current_pixel_refs_ = empty_pixel_refs_.Pointer(); 430 current_index_ = 0; 431 break; 432 } 433 } 434 435 // If there are no pixel refs at this grid cell, keep incrementing. 436 PixelRefMapKey key(current_x_, current_y_); 437 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key); 438 if (iter == picture_->pixel_refs_.end()) 439 continue; 440 441 // We found a non-empty list: store it and get the first pixel ref. 442 current_pixel_refs_ = &iter->second; 443 current_index_ = 0; 444 break; 445 } 446 return *this; 447 } 448 449 scoped_ptr<base::debug::ConvertableToTraceFormat> 450 Picture::AsTraceableRasterData(gfx::Rect rect, float scale) const { 451 scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue()); 452 raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release()); 453 raster_data->SetDouble("scale", scale); 454 raster_data->SetDouble("rect_x", rect.x()); 455 raster_data->SetDouble("rect_y", rect.y()); 456 raster_data->SetDouble("rect_width", rect.width()); 457 raster_data->SetDouble("rect_height", rect.height()); 458 return TracedValue::FromValue(raster_data.release()); 459 } 460 461 scoped_ptr<base::debug::ConvertableToTraceFormat> 462 Picture::AsTraceableRecordData() const { 463 scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue()); 464 record_data->Set("picture_id", TracedValue::CreateIDRef(this).release()); 465 record_data->SetInteger(benchmark_instrumentation::kWidth, 466 layer_rect_.width()); 467 record_data->SetInteger(benchmark_instrumentation::kHeight, 468 layer_rect_.height()); 469 return TracedValue::FromValue(record_data.release()); 470 } 471 472 } // namespace cc 473