1 // Copyright 2013 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/raster_worker_pool.h" 6 7 #include "base/json/json_writer.h" 8 #include "base/metrics/histogram.h" 9 #include "base/values.h" 10 #include "cc/debug/devtools_instrumentation.h" 11 #include "cc/debug/traced_value.h" 12 #include "cc/resources/picture_pile_impl.h" 13 #include "skia/ext/lazy_pixel_ref.h" 14 #include "skia/ext/paint_simplifier.h" 15 #include "third_party/skia/include/core/SkBitmap.h" 16 17 namespace cc { 18 19 namespace { 20 21 // Subclass of Allocator that takes a suitably allocated pointer and uses 22 // it as the pixel memory for the bitmap. 23 class IdentityAllocator : public SkBitmap::Allocator { 24 public: 25 explicit IdentityAllocator(void* buffer) : buffer_(buffer) {} 26 virtual bool allocPixelRef(SkBitmap* dst, SkColorTable*) OVERRIDE { 27 dst->setPixels(buffer_); 28 return true; 29 } 30 private: 31 void* buffer_; 32 }; 33 34 // Flag to indicate whether we should try and detect that 35 // a tile is of solid color. 36 const bool kUseColorEstimator = true; 37 38 class DisableLCDTextFilter : public SkDrawFilter { 39 public: 40 // SkDrawFilter interface. 41 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE { 42 if (type != SkDrawFilter::kText_Type) 43 return true; 44 45 paint->setLCDRenderText(false); 46 return true; 47 } 48 }; 49 50 class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask { 51 public: 52 RasterWorkerPoolTaskImpl(const Resource* resource, 53 PicturePileImpl* picture_pile, 54 gfx::Rect content_rect, 55 float contents_scale, 56 RasterMode raster_mode, 57 TileResolution tile_resolution, 58 int layer_id, 59 const void* tile_id, 60 int source_frame_number, 61 RenderingStatsInstrumentation* rendering_stats, 62 const RasterWorkerPool::RasterTask::Reply& reply, 63 TaskVector* dependencies) 64 : internal::RasterWorkerPoolTask(resource, dependencies), 65 picture_pile_(picture_pile), 66 content_rect_(content_rect), 67 contents_scale_(contents_scale), 68 raster_mode_(raster_mode), 69 tile_resolution_(tile_resolution), 70 layer_id_(layer_id), 71 tile_id_(tile_id), 72 source_frame_number_(source_frame_number), 73 rendering_stats_(rendering_stats), 74 reply_(reply) {} 75 76 void RunAnalysisOnThread(unsigned thread_index) { 77 TRACE_EVENT1("cc", 78 "RasterWorkerPoolTaskImpl::RunAnalysisOnThread", 79 "data", 80 TracedValue::FromValue(DataAsValue().release())); 81 82 DCHECK(picture_pile_.get()); 83 DCHECK(rendering_stats_); 84 85 PicturePileImpl* picture_clone = 86 picture_pile_->GetCloneForDrawingOnThread(thread_index); 87 88 DCHECK(picture_clone); 89 90 picture_clone->AnalyzeInRect( 91 content_rect_, contents_scale_, &analysis_, rendering_stats_); 92 93 // Record the solid color prediction. 94 UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed", 95 analysis_.is_solid_color); 96 97 // Clear the flag if we're not using the estimator. 98 analysis_.is_solid_color &= kUseColorEstimator; 99 } 100 101 bool RunRasterOnThread(unsigned thread_index, 102 void* buffer, 103 gfx::Size size, 104 int stride) { 105 TRACE_EVENT2( 106 "cc", "RasterWorkerPoolTaskImpl::RunRasterOnThread", 107 "data", 108 TracedValue::FromValue(DataAsValue().release()), 109 "raster_mode", 110 TracedValue::FromValue(RasterModeAsValue(raster_mode_).release())); 111 112 devtools_instrumentation::ScopedLayerTask raster_task( 113 devtools_instrumentation::kRasterTask, layer_id_); 114 115 DCHECK(picture_pile_.get()); 116 DCHECK(buffer); 117 118 if (analysis_.is_solid_color) 119 return false; 120 121 PicturePileImpl* picture_clone = 122 picture_pile_->GetCloneForDrawingOnThread(thread_index); 123 124 SkBitmap bitmap; 125 switch (resource()->format()) { 126 case RGBA_4444: 127 // Use the default stride if we will eventually convert this 128 // bitmap to 4444. 129 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 130 size.width(), 131 size.height()); 132 bitmap.allocPixels(); 133 break; 134 case RGBA_8888: 135 case BGRA_8888: 136 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 137 size.width(), 138 size.height(), 139 stride); 140 bitmap.setPixels(buffer); 141 break; 142 case LUMINANCE_8: 143 case RGB_565: 144 case ETC1: 145 NOTREACHED(); 146 break; 147 } 148 149 SkBitmapDevice device(bitmap); 150 SkCanvas canvas(&device); 151 skia::RefPtr<SkDrawFilter> draw_filter; 152 switch (raster_mode_) { 153 case LOW_QUALITY_RASTER_MODE: 154 draw_filter = skia::AdoptRef(new skia::PaintSimplifier); 155 break; 156 case HIGH_QUALITY_NO_LCD_RASTER_MODE: 157 draw_filter = skia::AdoptRef(new DisableLCDTextFilter); 158 break; 159 case HIGH_QUALITY_RASTER_MODE: 160 break; 161 case NUM_RASTER_MODES: 162 default: 163 NOTREACHED(); 164 } 165 166 canvas.setDrawFilter(draw_filter.get()); 167 168 base::TimeDelta prev_rasterize_time = 169 rendering_stats_->impl_thread_rendering_stats().rasterize_time; 170 171 // Only record rasterization time for highres tiles, because 172 // lowres tiles are not required for activation and therefore 173 // introduce noise in the measurement (sometimes they get rasterized 174 // before we draw and sometimes they aren't) 175 if (tile_resolution_ == HIGH_RESOLUTION) { 176 picture_clone->RasterToBitmap( 177 &canvas, content_rect_, contents_scale_, rendering_stats_); 178 } else { 179 picture_clone->RasterToBitmap( 180 &canvas, content_rect_, contents_scale_, NULL); 181 } 182 183 if (rendering_stats_->record_rendering_stats()) { 184 base::TimeDelta current_rasterize_time = 185 rendering_stats_->impl_thread_rendering_stats().rasterize_time; 186 HISTOGRAM_CUSTOM_COUNTS( 187 "Renderer4.PictureRasterTimeUS", 188 (current_rasterize_time - prev_rasterize_time).InMicroseconds(), 189 0, 190 100000, 191 100); 192 } 193 194 ChangeBitmapConfigIfNeeded(bitmap, buffer); 195 196 return true; 197 } 198 199 // Overridden from internal::RasterWorkerPoolTask: 200 virtual bool RunOnWorkerThread(unsigned thread_index, 201 void* buffer, 202 gfx::Size size, 203 int stride) 204 OVERRIDE { 205 RunAnalysisOnThread(thread_index); 206 return RunRasterOnThread(thread_index, buffer, size, stride); 207 } 208 virtual void CompleteOnOriginThread() OVERRIDE { 209 reply_.Run(analysis_, !HasFinishedRunning() || WasCanceled()); 210 } 211 212 protected: 213 virtual ~RasterWorkerPoolTaskImpl() {} 214 215 private: 216 scoped_ptr<base::Value> DataAsValue() const { 217 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); 218 res->Set("tile_id", TracedValue::CreateIDRef(tile_id_).release()); 219 res->Set("resolution", TileResolutionAsValue(tile_resolution_).release()); 220 res->SetInteger("source_frame_number", source_frame_number_); 221 res->SetInteger("layer_id", layer_id_); 222 return res.PassAs<base::Value>(); 223 } 224 225 void ChangeBitmapConfigIfNeeded(const SkBitmap& bitmap, 226 void* buffer) { 227 TRACE_EVENT0("cc", "RasterWorkerPoolTaskImpl::ChangeBitmapConfigIfNeeded"); 228 SkBitmap::Config config = SkBitmapConfig(resource()->format()); 229 if (bitmap.getConfig() != config) { 230 SkBitmap bitmap_dest; 231 IdentityAllocator allocator(buffer); 232 bitmap.copyTo(&bitmap_dest, config, &allocator); 233 // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the 234 // bitmap data. This check will be removed once crbug.com/293728 is fixed. 235 CHECK_EQ(0u, bitmap_dest.rowBytes() % 4); 236 } 237 } 238 239 PicturePileImpl::Analysis analysis_; 240 scoped_refptr<PicturePileImpl> picture_pile_; 241 gfx::Rect content_rect_; 242 float contents_scale_; 243 RasterMode raster_mode_; 244 TileResolution tile_resolution_; 245 int layer_id_; 246 const void* tile_id_; 247 int source_frame_number_; 248 RenderingStatsInstrumentation* rendering_stats_; 249 const RasterWorkerPool::RasterTask::Reply reply_; 250 251 DISALLOW_COPY_AND_ASSIGN(RasterWorkerPoolTaskImpl); 252 }; 253 254 class ImageDecodeWorkerPoolTaskImpl : public internal::WorkerPoolTask { 255 public: 256 ImageDecodeWorkerPoolTaskImpl(skia::LazyPixelRef* pixel_ref, 257 int layer_id, 258 RenderingStatsInstrumentation* rendering_stats, 259 const RasterWorkerPool::Task::Reply& reply) 260 : pixel_ref_(skia::SharePtr(pixel_ref)), 261 layer_id_(layer_id), 262 rendering_stats_(rendering_stats), 263 reply_(reply) {} 264 265 // Overridden from internal::WorkerPoolTask: 266 virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE { 267 TRACE_EVENT0("cc", "ImageDecodeWorkerPoolTaskImpl::RunOnWorkerThread"); 268 devtools_instrumentation::ScopedImageDecodeTask image_decode_task( 269 pixel_ref_.get()); 270 pixel_ref_->Decode(); 271 } 272 virtual void CompleteOnOriginThread() OVERRIDE { 273 reply_.Run(!HasFinishedRunning()); 274 } 275 276 protected: 277 virtual ~ImageDecodeWorkerPoolTaskImpl() {} 278 279 private: 280 skia::RefPtr<skia::LazyPixelRef> pixel_ref_; 281 int layer_id_; 282 RenderingStatsInstrumentation* rendering_stats_; 283 const RasterWorkerPool::Task::Reply reply_; 284 285 DISALLOW_COPY_AND_ASSIGN(ImageDecodeWorkerPoolTaskImpl); 286 }; 287 288 class RasterFinishedWorkerPoolTaskImpl : public internal::WorkerPoolTask { 289 public: 290 typedef base::Callback<void(const internal::WorkerPoolTask* source)> 291 Callback; 292 293 RasterFinishedWorkerPoolTaskImpl( 294 const Callback& on_raster_finished_callback) 295 : origin_loop_(base::MessageLoopProxy::current().get()), 296 on_raster_finished_callback_(on_raster_finished_callback) { 297 } 298 299 // Overridden from internal::WorkerPoolTask: 300 virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE { 301 TRACE_EVENT0("cc", "RasterFinishedWorkerPoolTaskImpl::RunOnWorkerThread"); 302 origin_loop_->PostTask( 303 FROM_HERE, 304 base::Bind(&RasterFinishedWorkerPoolTaskImpl::RunOnOriginThread, 305 this)); 306 } 307 virtual void CompleteOnOriginThread() OVERRIDE {} 308 309 private: 310 virtual ~RasterFinishedWorkerPoolTaskImpl() {} 311 312 void RunOnOriginThread() const { 313 on_raster_finished_callback_.Run(this); 314 } 315 316 scoped_refptr<base::MessageLoopProxy> origin_loop_; 317 const Callback on_raster_finished_callback_; 318 319 DISALLOW_COPY_AND_ASSIGN(RasterFinishedWorkerPoolTaskImpl); 320 }; 321 322 const char* kWorkerThreadNamePrefix = "CompositorRaster"; 323 324 } // namespace 325 326 namespace internal { 327 328 RasterWorkerPoolTask::RasterWorkerPoolTask( 329 const Resource* resource, TaskVector* dependencies) 330 : did_run_(false), 331 did_complete_(false), 332 was_canceled_(false), 333 resource_(resource) { 334 dependencies_.swap(*dependencies); 335 } 336 337 RasterWorkerPoolTask::~RasterWorkerPoolTask() { 338 } 339 340 void RasterWorkerPoolTask::DidRun(bool was_canceled) { 341 DCHECK(!did_run_); 342 did_run_ = true; 343 was_canceled_ = was_canceled; 344 } 345 346 bool RasterWorkerPoolTask::HasFinishedRunning() const { 347 return did_run_; 348 } 349 350 bool RasterWorkerPoolTask::WasCanceled() const { 351 return was_canceled_; 352 } 353 354 void RasterWorkerPoolTask::WillComplete() { 355 DCHECK(!did_complete_); 356 } 357 358 void RasterWorkerPoolTask::DidComplete() { 359 DCHECK(!did_complete_); 360 did_complete_ = true; 361 } 362 363 bool RasterWorkerPoolTask::HasCompleted() const { 364 return did_complete_; 365 } 366 367 } // namespace internal 368 369 RasterWorkerPool::Task::Set::Set() { 370 } 371 372 RasterWorkerPool::Task::Set::~Set() { 373 } 374 375 void RasterWorkerPool::Task::Set::Insert(const Task& task) { 376 DCHECK(!task.is_null()); 377 tasks_.push_back(task.internal_); 378 } 379 380 RasterWorkerPool::Task::Task() { 381 } 382 383 RasterWorkerPool::Task::Task(internal::WorkerPoolTask* internal) 384 : internal_(internal) { 385 } 386 387 RasterWorkerPool::Task::~Task() { 388 } 389 390 void RasterWorkerPool::Task::Reset() { 391 internal_ = NULL; 392 } 393 394 RasterWorkerPool::RasterTask::Queue::Queue() { 395 } 396 397 RasterWorkerPool::RasterTask::Queue::~Queue() { 398 } 399 400 void RasterWorkerPool::RasterTask::Queue::Append( 401 const RasterTask& task, bool required_for_activation) { 402 DCHECK(!task.is_null()); 403 tasks_.push_back(task.internal_); 404 if (required_for_activation) 405 tasks_required_for_activation_.insert(task.internal_.get()); 406 } 407 408 RasterWorkerPool::RasterTask::RasterTask() { 409 } 410 411 RasterWorkerPool::RasterTask::RasterTask( 412 internal::RasterWorkerPoolTask* internal) 413 : internal_(internal) { 414 } 415 416 void RasterWorkerPool::RasterTask::Reset() { 417 internal_ = NULL; 418 } 419 420 RasterWorkerPool::RasterTask::~RasterTask() { 421 } 422 423 // static 424 RasterWorkerPool::RasterTask RasterWorkerPool::CreateRasterTask( 425 const Resource* resource, 426 PicturePileImpl* picture_pile, 427 gfx::Rect content_rect, 428 float contents_scale, 429 RasterMode raster_mode, 430 TileResolution tile_resolution, 431 int layer_id, 432 const void* tile_id, 433 int source_frame_number, 434 RenderingStatsInstrumentation* rendering_stats, 435 const RasterTask::Reply& reply, 436 Task::Set* dependencies) { 437 return RasterTask( 438 new RasterWorkerPoolTaskImpl(resource, 439 picture_pile, 440 content_rect, 441 contents_scale, 442 raster_mode, 443 tile_resolution, 444 layer_id, 445 tile_id, 446 source_frame_number, 447 rendering_stats, 448 reply, 449 &dependencies->tasks_)); 450 } 451 452 // static 453 RasterWorkerPool::Task RasterWorkerPool::CreateImageDecodeTask( 454 skia::LazyPixelRef* pixel_ref, 455 int layer_id, 456 RenderingStatsInstrumentation* stats_instrumentation, 457 const Task::Reply& reply) { 458 return Task(new ImageDecodeWorkerPoolTaskImpl(pixel_ref, 459 layer_id, 460 stats_instrumentation, 461 reply)); 462 } 463 464 RasterWorkerPool::RasterWorkerPool(ResourceProvider* resource_provider, 465 size_t num_threads) 466 : WorkerPool(num_threads, kWorkerThreadNamePrefix), 467 client_(NULL), 468 resource_provider_(resource_provider), 469 weak_ptr_factory_(this) { 470 } 471 472 RasterWorkerPool::~RasterWorkerPool() { 473 } 474 475 void RasterWorkerPool::SetClient(RasterWorkerPoolClient* client) { 476 client_ = client; 477 } 478 479 void RasterWorkerPool::Shutdown() { 480 raster_tasks_.clear(); 481 TaskGraph empty; 482 SetTaskGraph(&empty); 483 WorkerPool::Shutdown(); 484 weak_ptr_factory_.InvalidateWeakPtrs(); 485 } 486 487 void RasterWorkerPool::SetRasterTasks(RasterTask::Queue* queue) { 488 raster_tasks_.swap(queue->tasks_); 489 raster_tasks_required_for_activation_.swap( 490 queue->tasks_required_for_activation_); 491 } 492 493 bool RasterWorkerPool::IsRasterTaskRequiredForActivation( 494 internal::RasterWorkerPoolTask* task) const { 495 return 496 raster_tasks_required_for_activation_.find(task) != 497 raster_tasks_required_for_activation_.end(); 498 } 499 500 scoped_refptr<internal::WorkerPoolTask> 501 RasterWorkerPool::CreateRasterFinishedTask() { 502 return make_scoped_refptr( 503 new RasterFinishedWorkerPoolTaskImpl( 504 base::Bind(&RasterWorkerPool::OnRasterFinished, 505 weak_ptr_factory_.GetWeakPtr()))); 506 } 507 508 scoped_refptr<internal::WorkerPoolTask> 509 RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask() { 510 return make_scoped_refptr( 511 new RasterFinishedWorkerPoolTaskImpl( 512 base::Bind(&RasterWorkerPool::OnRasterRequiredForActivationFinished, 513 weak_ptr_factory_.GetWeakPtr()))); 514 } 515 516 void RasterWorkerPool::OnRasterFinished( 517 const internal::WorkerPoolTask* source) { 518 TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterFinished"); 519 520 // Early out if current |raster_finished_task_| is not the source. 521 if (source != raster_finished_task_.get()) 522 return; 523 524 OnRasterTasksFinished(); 525 } 526 527 void RasterWorkerPool::OnRasterRequiredForActivationFinished( 528 const internal::WorkerPoolTask* source) { 529 TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterRequiredForActivationFinished"); 530 531 // Early out if current |raster_required_for_activation_finished_task_| 532 // is not the source. 533 if (source != raster_required_for_activation_finished_task_.get()) 534 return; 535 536 OnRasterTasksRequiredForActivationFinished(); 537 } 538 539 scoped_ptr<base::Value> RasterWorkerPool::ScheduledStateAsValue() const { 540 scoped_ptr<base::DictionaryValue> scheduled_state(new base::DictionaryValue); 541 scheduled_state->SetInteger("task_count", raster_tasks_.size()); 542 scheduled_state->SetInteger("task_required_for_activation_count", 543 raster_tasks_required_for_activation_.size()); 544 return scheduled_state.PassAs<base::Value>(); 545 } 546 547 // static 548 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForTask( 549 internal::WorkerPoolTask* task, 550 unsigned priority, 551 TaskGraph* graph) { 552 internal::GraphNode* node = new internal::GraphNode(task, priority); 553 DCHECK(graph->find(task) == graph->end()); 554 graph->set(task, make_scoped_ptr(node)); 555 return node; 556 } 557 558 // static 559 internal::GraphNode* RasterWorkerPool::CreateGraphNodeForRasterTask( 560 internal::WorkerPoolTask* raster_task, 561 const TaskVector& decode_tasks, 562 unsigned priority, 563 TaskGraph* graph) { 564 DCHECK(!raster_task->HasCompleted()); 565 566 internal::GraphNode* raster_node = CreateGraphNodeForTask( 567 raster_task, priority, graph); 568 569 // Insert image decode tasks. 570 for (TaskVector::const_iterator it = decode_tasks.begin(); 571 it != decode_tasks.end(); ++it) { 572 internal::WorkerPoolTask* decode_task = it->get(); 573 574 // Skip if already decoded. 575 if (decode_task->HasCompleted()) 576 continue; 577 578 raster_node->add_dependency(); 579 580 // Check if decode task already exists in graph. 581 GraphNodeMap::iterator decode_it = graph->find(decode_task); 582 if (decode_it != graph->end()) { 583 internal::GraphNode* decode_node = decode_it->second; 584 decode_node->add_dependent(raster_node); 585 continue; 586 } 587 588 internal::GraphNode* decode_node = CreateGraphNodeForTask( 589 decode_task, priority, graph); 590 decode_node->add_dependent(raster_node); 591 } 592 593 return raster_node; 594 } 595 596 } // namespace cc 597