Chromium Code Reviews| Index: cc/resources/pixel_buffer_raster_worker_pool.cc |
| diff --git a/cc/resources/pixel_buffer_raster_worker_pool.cc b/cc/resources/pixel_buffer_raster_worker_pool.cc |
| index bbdb5321f80ebbaafd4622944329b106699e406f..9f15da85dfc4f2418d018d0efdd7918fb8f3b149 100644 |
| --- a/cc/resources/pixel_buffer_raster_worker_pool.cc |
| +++ b/cc/resources/pixel_buffer_raster_worker_pool.cc |
| @@ -4,6 +4,8 @@ |
| #include "cc/resources/pixel_buffer_raster_worker_pool.h" |
| +#include <vector> |
| + |
| #include "base/debug/trace_event.h" |
| #include "cc/resources/resource.h" |
| #include "third_party/skia/include/core/SkDevice.h" |
| @@ -84,11 +86,14 @@ const size_t kMaxPendingRasterBytes = |
| PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool( |
| ResourceProvider* resource_provider, |
| - size_t num_threads) : RasterWorkerPool(resource_provider, num_threads), |
| - shutdown_(false), |
| - bytes_pending_upload_(0), |
| - has_performed_uploads_since_last_flush_(false), |
| - check_for_completed_raster_tasks_pending_(false) { |
| + size_t num_threads) |
| + : RasterWorkerPool(resource_provider, num_threads), |
| + shutdown_(false), |
| + bytes_pending_upload_(0), |
| + has_performed_uploads_since_last_flush_(false), |
| + check_for_completed_raster_tasks_pending_(false), |
| + finished_running_tasks_pending_(false), |
| + finished_running_tasks_required_for_activation_pending_(false) { |
| } |
| PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() { |
| @@ -102,7 +107,10 @@ PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() { |
| void PixelBufferRasterWorkerPool::Shutdown() { |
| shutdown_ = true; |
| RasterWorkerPool::Shutdown(); |
| - CheckForCompletedRasterTasks(); |
| + RasterWorkerPool::CheckForCompletedTasks(); |
| + CheckForCompletedUploads(); |
| + check_for_completed_raster_tasks_callback_.Cancel(); |
| + check_for_completed_raster_tasks_pending_ = false; |
| for (TaskMap::iterator it = pixel_buffer_tasks_.begin(); |
| it != pixel_buffer_tasks_.end(); ++it) { |
| internal::RasterWorkerPoolTask* task = it->first; |
| @@ -114,6 +122,7 @@ void PixelBufferRasterWorkerPool::Shutdown() { |
| completed_tasks_.push_back(task); |
| } |
| } |
| + DCHECK_EQ(completed_tasks_.size(), pixel_buffer_tasks_.size()); |
| } |
| void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) { |
| @@ -121,6 +130,9 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) { |
| RasterWorkerPool::SetRasterTasks(queue); |
| + finished_running_tasks_pending_ = true; |
| + finished_running_tasks_required_for_activation_pending_ = true; |
| + |
| // Build new pixel buffer task set. |
| TaskMap new_pixel_buffer_tasks; |
| for (RasterTaskVector::const_iterator it = raster_tasks().begin(); |
| @@ -160,13 +172,31 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) { |
| } |
| } |
| + tasks_required_for_activation_.clear(); |
| + for (TaskMap::iterator it = new_pixel_buffer_tasks.begin(); |
| + it != new_pixel_buffer_tasks.end(); ++it) { |
| + internal::RasterWorkerPoolTask* task = it->first; |
| + if (IsRasterTaskRequiredForActivation(task)) |
| + tasks_required_for_activation_.insert(task); |
| + } |
| + |
| pixel_buffer_tasks_.swap(new_pixel_buffer_tasks); |
| - // This will schedule more tasks after checking for completed raster |
| - // tasks. It's worth checking for completed tasks when ScheduleTasks() |
| - // is called as priorities might have changed and this allows us to |
| - // schedule as many new top priority tasks as possible. |
| - CheckForCompletedRasterTasks(); |
| + // Check for completed tasks when ScheduleTasks() is called as |
| + // priorities might have changed and this maximizes the number |
| + // of top priority tasks that are scheduled. |
| + RasterWorkerPool::CheckForCompletedTasks(); |
| + CheckForCompletedUploads(); |
| + FlushUploads(); |
| + |
| + // Schedule new tasks. |
| + ScheduleMoreTasks(); |
| + |
| + // Cancel any pending check for completed raster tasks and schedule |
| + // another check. |
| + check_for_completed_raster_tasks_callback_.Cancel(); |
| + check_for_completed_raster_tasks_pending_ = false; |
| + ScheduleCheckForCompletedRasterTasks(); |
| } |
| void PixelBufferRasterWorkerPool::CheckForCompletedTasks() { |
| @@ -176,8 +206,11 @@ void PixelBufferRasterWorkerPool::CheckForCompletedTasks() { |
| CheckForCompletedUploads(); |
| FlushUploads(); |
| - while (!completed_tasks_.empty()) { |
| - internal::RasterWorkerPoolTask* task = completed_tasks_.front().get(); |
| + TaskDeque completed_tasks; |
| + completed_tasks_.swap(completed_tasks); |
| + |
| + while (!completed_tasks.empty()) { |
| + internal::RasterWorkerPoolTask* task = completed_tasks.front().get(); |
| DCHECK(pixel_buffer_tasks_.find(task) != pixel_buffer_tasks_.end()); |
| pixel_buffer_tasks_.erase(task); |
| @@ -186,17 +219,22 @@ void PixelBufferRasterWorkerPool::CheckForCompletedTasks() { |
| task->CompleteOnOriginThread(); |
| task->DidComplete(); |
| - completed_tasks_.pop_front(); |
| + completed_tasks.pop_front(); |
| } |
| } |
| void PixelBufferRasterWorkerPool::OnRasterTasksFinished() { |
| - // Call CheckForCompletedTasks() when we've finished running all raster |
| - // tasks needed since last time ScheduleMoreTasks() was called. This |
| + // Call CheckForCompletedRasterTasks() when we've finished running all |
| + // raster tasks needed since last time ScheduleTasks() was called. This |
| // reduces latency when processing only a small number of raster tasks. |
| CheckForCompletedRasterTasks(); |
| } |
| +void PixelBufferRasterWorkerPool::OnRasterTasksRequiredForActivationFinished() { |
| + // Handle this the same way as when finished running all raster tasks. |
| + OnRasterTasksFinished(); |
| +} |
| + |
| void PixelBufferRasterWorkerPool::FlushUploads() { |
| if (!has_performed_uploads_since_last_flush_) |
| return; |
| @@ -272,6 +310,8 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() { |
| task) == completed_tasks_.end()); |
| completed_tasks_.push_back(task); |
| + tasks_required_for_activation_.erase(task); |
| + |
| tasks_with_completed_uploads.pop_front(); |
| } |
| } |
| @@ -301,21 +341,43 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() { |
| CheckForCompletedUploads(); |
| FlushUploads(); |
| - ScheduleMoreTasks(); |
| + // Determine if client should be notified and update pending notification |
| + // status before scheduling more raster tasks. |
| + bool notify_client_that_finished_running_tasks_required_for_activation = |
| + NotifyClientThatFinishedRunningTasksRequiredForActivation(); |
|
vmpstr
2013/06/28 18:12:35
Maybe something like AreTaskRequiredForActivationF
reveman
2013/06/28 20:18:41
Cleaned this up a bit in latest patch. Let me know
|
| + bool notify_client_that_finished_running_tasks = |
| + NotifyClientThatFinishedRunningTasks(); |
| - // Make sure another check for completed uploads is scheduled |
| - // while there is still pending uploads left. |
| - if (!tasks_with_pending_upload_.empty()) |
| + if (PendingRasterTaskCount()) |
| + ScheduleMoreTasks(); |
| + |
| + // Schedule another check for completed raster tasks while there are |
| + // pending raster tasks or pending uploads. |
| + if (PendingRasterTaskCount() || !tasks_with_pending_upload_.empty()) |
| ScheduleCheckForCompletedRasterTasks(); |
| + |
| + if (notify_client_that_finished_running_tasks_required_for_activation) |
| + client()->DidFinishedRunningTasksRequiredForActivation(); |
| + if (notify_client_that_finished_running_tasks) |
| + client()->DidFinishedRunningTasks(); |
| } |
| void PixelBufferRasterWorkerPool::ScheduleMoreTasks() { |
| TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleMoreTasks"); |
| + enum RasterTaskType { |
| + PREPAINT_TYPE = 0, |
| + REQUIRED_FOR_ACTIVATION_TYPE = 1, |
| + NUM_TYPES = 2 |
| + }; |
| + // TODO(reveman): Use StackVector instead. |
| + std::vector<GraphNode*> tasks[NUM_TYPES]; |
| + unsigned priority = 2u; // 0-1 reserved for RasterFinished tasks. |
| + TaskGraph graph; |
| + |
| size_t bytes_pending_upload = bytes_pending_upload_; |
| size_t bytes_pending_raster = 0; |
| - RasterTaskGraph graph; |
| for (RasterTaskVector::const_iterator it = raster_tasks().begin(); |
| it != raster_tasks().end(); ++it) { |
| internal::RasterWorkerPoolTask* task = it->get(); |
| @@ -359,9 +421,17 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() { |
| bytes_pending_raster = new_bytes_pending_raster; |
| bytes_pending_upload = new_bytes_pending_upload; |
| + RasterTaskType type = IsRasterTaskRequiredForActivation(task) ? |
| + REQUIRED_FOR_ACTIVATION_TYPE : |
| + PREPAINT_TYPE; |
| + |
| // Use existing pixel buffer task if available. |
| if (pixel_buffer_task) { |
| - graph.InsertRasterTask(pixel_buffer_task, task->dependencies()); |
| + tasks[type].push_back( |
| + CreateGraphNodeForRasterTask(pixel_buffer_task, |
| + task->dependencies(), |
| + priority++, |
| + &graph)); |
| continue; |
| } |
| @@ -382,16 +452,70 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() { |
| base::Unretained(this), |
| make_scoped_refptr(task)))); |
| pixel_buffer_tasks_[task] = new_pixel_buffer_task; |
| - graph.InsertRasterTask(new_pixel_buffer_task.get(), task->dependencies()); |
| + tasks[type].push_back( |
| + CreateGraphNodeForRasterTask(new_pixel_buffer_task.get(), |
| + task->dependencies(), |
| + priority++, |
| + &graph)); |
| + } |
| + |
| + scoped_refptr<internal::WorkerPoolTask> |
| + new_raster_required_for_activation_finished_task; |
| + |
| + DCHECK_LE(tasks[REQUIRED_FOR_ACTIVATION_TYPE].size(), |
| + tasks_required_for_activation_.size()); |
| + // Schedule OnRasterTasksRequiredForActivationFinished call when |
|
vmpstr
2013/06/28 18:12:35
nit: Schedule OnRaster.. call only when
reveman
2013/06/28 20:18:41
Done.
|
| + // notification is pending and throttling is not preventing |
| + // all pending tasks required for activation from being scheduled. |
| + if (tasks[REQUIRED_FOR_ACTIVATION_TYPE].size() == |
| + tasks_required_for_activation_.size() && |
| + finished_running_tasks_required_for_activation_pending_) { |
| + new_raster_required_for_activation_finished_task = |
| + CreateRasterRequiredForActivationFinishedTask(); |
| + GraphNode* raster_required_for_activation_finished_node = |
| + CreateGraphNodeForTask( |
| + new_raster_required_for_activation_finished_task.get(), |
| + 0u, // Priority 0 |
| + &graph); |
| + for (unsigned j = 0; |
|
vmpstr
2013/06/28 18:12:35
I still think this loop, and the inner loop around
reveman
2013/06/28 20:18:41
Move inner loop to a separate function.
|
| + j < tasks[REQUIRED_FOR_ACTIVATION_TYPE].size(); |
| + ++j) { |
| + raster_required_for_activation_finished_node->add_dependency(); |
| + tasks[REQUIRED_FOR_ACTIVATION_TYPE][j]->add_dependent( |
| + raster_required_for_activation_finished_node); |
| + } |
| + } |
| + |
| + scoped_refptr<internal::WorkerPoolTask> new_raster_finished_task; |
| + |
| + DCHECK_LE(tasks[PREPAINT_TYPE].size() + |
| + tasks[REQUIRED_FOR_ACTIVATION_TYPE].size(), |
| + PendingRasterTaskCount()); |
| + // Schedule OnRasterTasksFinished call when notification is pending |
|
vmpstr
2013/06/28 18:12:35
nit: ... only when ...
reveman
2013/06/28 20:18:41
Done.
|
| + // and throttling is not preventing all pending tasks from being |
| + // scheduled. |
| + if ((tasks[PREPAINT_TYPE].size() + |
| + tasks[REQUIRED_FOR_ACTIVATION_TYPE].size()) == |
| + PendingRasterTaskCount() && |
| + finished_running_tasks_pending_) { |
| + new_raster_finished_task = CreateRasterFinishedTask(); |
| + GraphNode* raster_finished_node = |
| + CreateGraphNodeForTask(new_raster_finished_task.get(), |
| + 1u, // Priority 1 |
| + &graph); |
| + for (unsigned type = 0; type < NUM_TYPES; ++type) { |
| + for (unsigned i = 0; i < tasks[type].size(); ++i) { |
| + raster_finished_node->add_dependency(); |
| + tasks[type][i]->add_dependent(raster_finished_node); |
| + } |
| + } |
| } |
| - SetRasterTaskGraph(&graph); |
| + SetTaskGraph(&graph); |
| - // At least one task that could need an upload is now pending, schedule |
| - // a check for completed raster tasks to ensure this upload is dispatched |
| - // without too much latency. |
| - if (bytes_pending_raster) |
| - ScheduleCheckForCompletedRasterTasks(); |
| + set_raster_finished_task(new_raster_finished_task); |
| + set_raster_required_for_activation_finished_task( |
| + new_raster_required_for_activation_finished_task); |
| } |
| void PixelBufferRasterWorkerPool::OnRasterTaskCompleted( |
| @@ -414,6 +538,7 @@ void PixelBufferRasterWorkerPool::OnRasterTaskCompleted( |
| completed_tasks_.end(), |
| task) == completed_tasks_.end()); |
| completed_tasks_.push_back(task); |
| + tasks_required_for_activation_.erase(task); |
| return; |
| } |
| @@ -424,4 +549,37 @@ void PixelBufferRasterWorkerPool::OnRasterTaskCompleted( |
| tasks_with_pending_upload_.push_back(task); |
| } |
| +unsigned PixelBufferRasterWorkerPool::PendingRasterTaskCount() const { |
| + unsigned num_completed_raster_tasks = |
| + tasks_with_pending_upload_.size() + completed_tasks_.size(); |
| + DCHECK_GE(pixel_buffer_tasks_.size(), num_completed_raster_tasks); |
| + return pixel_buffer_tasks_.size() - num_completed_raster_tasks; |
| +} |
| + |
| +bool PixelBufferRasterWorkerPool:: |
| + NotifyClientThatFinishedRunningTasksRequiredForActivation() { |
| + if (!finished_running_tasks_required_for_activation_pending_) |
| + return false; |
| + |
| + if (!tasks_required_for_activation_.empty()) |
| + return false; |
| + |
| + finished_running_tasks_required_for_activation_pending_ = false; |
| + return true; |
| +} |
| + |
| +bool PixelBufferRasterWorkerPool::NotifyClientThatFinishedRunningTasks() { |
| + if (!finished_running_tasks_pending_) |
| + return false; |
| + |
| + if (PendingRasterTaskCount()) |
| + return false; |
| + |
| + if (!tasks_with_pending_upload_.empty()) |
| + return false; |
| + |
| + finished_running_tasks_pending_ = false; |
| + return true; |
| +} |
| + |
| } // namespace cc |