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