| 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..3d8741109c1c58148b661971f7feee359279fd8d 100644
|
| --- a/cc/resources/pixel_buffer_raster_worker_pool.cc
|
| +++ b/cc/resources/pixel_buffer_raster_worker_pool.cc
|
| @@ -4,7 +4,10 @@
|
|
|
| #include "cc/resources/pixel_buffer_raster_worker_pool.h"
|
|
|
| +#include "base/containers/stack_container.h"
|
| #include "base/debug/trace_event.h"
|
| +#include "base/values.h"
|
| +#include "cc/debug/traced_value.h"
|
| #include "cc/resources/resource.h"
|
| #include "third_party/skia/include/core/SkDevice.h"
|
|
|
| @@ -77,18 +80,37 @@ const size_t kMaxPendingUploadBytes = 16 * 2 * kMaxBytesUploadedPerMs;
|
|
|
| const int kCheckForCompletedRasterTasksDelayMs = 6;
|
|
|
| -const size_t kMaxPendingRasterBytes =
|
| - kMaxBytesUploadedPerMs * kCheckForCompletedRasterTasksDelayMs;
|
| +const size_t kMaxScheduledRasterTasks = 48;
|
| +
|
| +typedef base::StackVector<internal::GraphNode*,
|
| + kMaxScheduledRasterTasks> NodeVector;
|
| +
|
| +void AddDependenciesToGraphNode(
|
| + internal::GraphNode* node,
|
| + const NodeVector::ContainerType& dependencies) {
|
| + for (NodeVector::ContainerType::const_iterator it = dependencies.begin();
|
| + it != dependencies.end(); ++it) {
|
| + internal::GraphNode* dependency = *it;
|
| +
|
| + node->add_dependency();
|
| + dependency->add_dependent(node);
|
| + }
|
| +}
|
|
|
| } // namespace
|
|
|
| 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),
|
| + scheduled_raster_task_count_(0),
|
| + bytes_pending_upload_(0),
|
| + has_performed_uploads_since_last_flush_(false),
|
| + check_for_completed_raster_tasks_pending_(false),
|
| + should_notify_client_if_no_tasks_are_pending_(false),
|
| + should_notify_client_if_no_tasks_required_for_activation_are_pending_(
|
| + false) {
|
| }
|
|
|
| PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() {
|
| @@ -102,7 +124,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 +139,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 +147,12 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
|
|
|
| RasterWorkerPool::SetRasterTasks(queue);
|
|
|
| + if (!should_notify_client_if_no_tasks_are_pending_)
|
| + TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
|
| +
|
| + should_notify_client_if_no_tasks_are_pending_ = true;
|
| + should_notify_client_if_no_tasks_required_for_activation_are_pending_ = true;
|
| +
|
| // Build new pixel buffer task set.
|
| TaskMap new_pixel_buffer_tasks;
|
| for (RasterTaskVector::const_iterator it = raster_tasks().begin();
|
| @@ -160,13 +192,35 @@ 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();
|
| +
|
| + TRACE_EVENT_ASYNC_STEP1(
|
| + "cc", "ScheduledTasks", this, StateName(),
|
| + "state", TracedValue::FromValue(StateAsValue().release()));
|
| }
|
|
|
| void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
|
| @@ -176,8 +230,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,14 +243,33 @@ 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
|
| - // reduces latency when processing only a small number of raster tasks.
|
| + // |should_notify_client_if_no_tasks_are_pending_| can be set to false as
|
| + // a result of a scheduled CheckForCompletedRasterTasks() call. No need to
|
| + // perform another check in that case as we've already notified the client.
|
| + if (!should_notify_client_if_no_tasks_are_pending_)
|
| + return;
|
| +
|
| + // Call CheckForCompletedRasterTasks() when we've finished running all
|
| + // raster tasks needed since last time ScheduleTasks() was called.
|
| + // This reduces latency between the time when all tasks have finished
|
| + // running and the time when the client is notified.
|
| + CheckForCompletedRasterTasks();
|
| +}
|
| +
|
| +void PixelBufferRasterWorkerPool::OnRasterTasksRequiredForActivationFinished() {
|
| + // Analogous to OnRasterTasksFinished(), there's no need to call
|
| + // CheckForCompletedRasterTasks() if the client has already been notified.
|
| + if (!should_notify_client_if_no_tasks_required_for_activation_are_pending_)
|
| + return;
|
| +
|
| + // This reduces latency between the time when all tasks required for
|
| + // activation have finished running and the time when the client is
|
| + // notified.
|
| CheckForCompletedRasterTasks();
|
| }
|
|
|
| @@ -272,6 +348,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();
|
| }
|
| }
|
| @@ -294,6 +372,8 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
|
| TRACE_EVENT0(
|
| "cc", "PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks");
|
|
|
| + DCHECK(should_notify_client_if_no_tasks_are_pending_);
|
| +
|
| check_for_completed_raster_tasks_callback_.Cancel();
|
| check_for_completed_raster_tasks_pending_ = false;
|
|
|
| @@ -301,21 +381,55 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
|
| CheckForCompletedUploads();
|
| FlushUploads();
|
|
|
| - ScheduleMoreTasks();
|
| -
|
| - // Make sure another check for completed uploads is scheduled
|
| - // while there is still pending uploads left.
|
| - if (!tasks_with_pending_upload_.empty())
|
| + // Determine what client notifications to generate.
|
| + bool will_notify_client_that_no_tasks_required_for_activation_are_pending =
|
| + (should_notify_client_if_no_tasks_required_for_activation_are_pending_ &&
|
| + !HasPendingTasksRequiredForActivation());
|
| + bool will_notify_client_that_no_tasks_are_pending =
|
| + (should_notify_client_if_no_tasks_are_pending_ &&
|
| + !HasPendingTasks());
|
| +
|
| + // Adjust the need to generate notifications before scheduling more tasks.
|
| + should_notify_client_if_no_tasks_required_for_activation_are_pending_ &=
|
| + !will_notify_client_that_no_tasks_required_for_activation_are_pending;
|
| + should_notify_client_if_no_tasks_are_pending_ &=
|
| + !will_notify_client_that_no_tasks_are_pending;
|
| +
|
| + if (PendingRasterTaskCount())
|
| + ScheduleMoreTasks();
|
| +
|
| + TRACE_EVENT_ASYNC_STEP1(
|
| + "cc", "ScheduledTasks", this, StateName(),
|
| + "state", TracedValue::FromValue(StateAsValue().release()));
|
| +
|
| + // Schedule another check for completed raster tasks while there are
|
| + // pending raster tasks or pending uploads.
|
| + if (HasPendingTasks())
|
| ScheduleCheckForCompletedRasterTasks();
|
| +
|
| + // Generate client notifications.
|
| + if (will_notify_client_that_no_tasks_required_for_activation_are_pending)
|
| + client()->DidFinishedRunningTasksRequiredForActivation();
|
| + if (will_notify_client_that_no_tasks_are_pending) {
|
| + TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
|
| + client()->DidFinishedRunningTasks();
|
| + }
|
| }
|
|
|
| void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
|
| TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleMoreTasks");
|
|
|
| + enum RasterTaskType {
|
| + PREPAINT_TYPE = 0,
|
| + REQUIRED_FOR_ACTIVATION_TYPE = 1,
|
| + NUM_TYPES = 2
|
| + };
|
| + NodeVector 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();
|
| @@ -347,21 +461,28 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
|
| continue;
|
| }
|
|
|
| - // Throttle raster tasks based on bytes pending if raster has not
|
| - // finished.
|
| - size_t new_bytes_pending_raster = bytes_pending_raster;
|
| - new_bytes_pending_raster += task->resource()->bytes();
|
| - if (new_bytes_pending_raster > kMaxPendingRasterBytes)
|
| + // Throttle raster tasks based on kMaxScheduledRasterTasks.
|
| + size_t scheduled_raster_task_count =
|
| + tasks[PREPAINT_TYPE].container().size() +
|
| + tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
|
| + if (scheduled_raster_task_count >= kMaxScheduledRasterTasks)
|
| break;
|
|
|
| - // Update both |bytes_pending_raster| and |bytes_pending_upload|
|
| - // now that task has cleared all throttling limits.
|
| - bytes_pending_raster = new_bytes_pending_raster;
|
| + // Update |bytes_pending_upload| now that task has cleared all
|
| + // throttling limits.
|
| 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].container().push_back(
|
| + CreateGraphNodeForRasterTask(pixel_buffer_task,
|
| + task->dependencies(),
|
| + priority++,
|
| + &graph));
|
| continue;
|
| }
|
|
|
| @@ -382,16 +503,67 @@ 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].container().push_back(
|
| + CreateGraphNodeForRasterTask(new_pixel_buffer_task.get(),
|
| + task->dependencies(),
|
| + priority++,
|
| + &graph));
|
| }
|
|
|
| - SetRasterTaskGraph(&graph);
|
| + scoped_refptr<internal::WorkerPoolTask>
|
| + new_raster_required_for_activation_finished_task;
|
| +
|
| + size_t scheduled_raster_task_required_for_activation_count =
|
| + tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
|
| + DCHECK_LE(scheduled_raster_task_required_for_activation_count,
|
| + tasks_required_for_activation_.size());
|
| + // Schedule OnRasterTasksRequiredForActivationFinished call only when
|
| + // notification is pending and throttling is not preventing all pending
|
| + // tasks required for activation from being scheduled.
|
| + if (scheduled_raster_task_required_for_activation_count ==
|
| + tasks_required_for_activation_.size() &&
|
| + should_notify_client_if_no_tasks_required_for_activation_are_pending_) {
|
| + new_raster_required_for_activation_finished_task =
|
| + CreateRasterRequiredForActivationFinishedTask();
|
| + internal::GraphNode* raster_required_for_activation_finished_node =
|
| + CreateGraphNodeForTask(
|
| + new_raster_required_for_activation_finished_task.get(),
|
| + 0u, // Priority 0
|
| + &graph);
|
| + AddDependenciesToGraphNode(
|
| + raster_required_for_activation_finished_node,
|
| + tasks[REQUIRED_FOR_ACTIVATION_TYPE].container());
|
| + }
|
|
|
| - // 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();
|
| + scoped_refptr<internal::WorkerPoolTask> new_raster_finished_task;
|
| +
|
| + size_t scheduled_raster_task_count =
|
| + tasks[PREPAINT_TYPE].container().size() +
|
| + tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
|
| + DCHECK_LE(scheduled_raster_task_count, PendingRasterTaskCount());
|
| + // Schedule OnRasterTasksFinished call only when notification is pending
|
| + // and throttling is not preventing all pending tasks from being scheduled.
|
| + if (scheduled_raster_task_count == PendingRasterTaskCount() &&
|
| + should_notify_client_if_no_tasks_are_pending_) {
|
| + new_raster_finished_task = CreateRasterFinishedTask();
|
| + internal::GraphNode* raster_finished_node =
|
| + CreateGraphNodeForTask(new_raster_finished_task.get(),
|
| + 1u, // Priority 1
|
| + &graph);
|
| + for (unsigned type = 0; type < NUM_TYPES; ++type) {
|
| + AddDependenciesToGraphNode(
|
| + raster_finished_node,
|
| + tasks[type].container());
|
| + }
|
| + }
|
| +
|
| + SetTaskGraph(&graph);
|
| +
|
| + scheduled_raster_task_count_ = scheduled_raster_task_count;
|
| +
|
| + 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 +586,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 +597,55 @@ 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::HasPendingTasks() const {
|
| + return PendingRasterTaskCount() || !tasks_with_pending_upload_.empty();
|
| +}
|
| +
|
| +bool PixelBufferRasterWorkerPool::HasPendingTasksRequiredForActivation() const {
|
| + return !tasks_required_for_activation_.empty();
|
| +}
|
| +
|
| +const char* PixelBufferRasterWorkerPool::StateName() const {
|
| + if (scheduled_raster_task_count_)
|
| + return "rasterizing";
|
| + if (PendingRasterTaskCount())
|
| + return "throttled";
|
| + if (!tasks_with_pending_upload_.empty())
|
| + return "waiting_for_uploads";
|
| +
|
| + return "finishing";
|
| +}
|
| +
|
| +scoped_ptr<base::Value> PixelBufferRasterWorkerPool::StateAsValue() const {
|
| + scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
|
| +
|
| + state->SetInteger("completed_count", completed_tasks_.size());
|
| + state->SetInteger("pending_count", pixel_buffer_tasks_.size());
|
| + state->SetInteger("pending_upload_count", tasks_with_pending_upload_.size());
|
| + state->SetInteger("required_for_activation_count",
|
| + tasks_required_for_activation_.size());
|
| + state->Set("scheduled_state", ScheduledStateAsValue().release());
|
| + state->Set("throttle_state", ThrottleStateAsValue().release());
|
| + return state.PassAs<base::Value>();
|
| +}
|
| +
|
| +scoped_ptr<base::Value> PixelBufferRasterWorkerPool::ThrottleStateAsValue()
|
| + const {
|
| + scoped_ptr<base::DictionaryValue> throttle_state(new base::DictionaryValue);
|
| +
|
| + throttle_state->SetInteger("bytes_available_for_upload",
|
| + kMaxPendingUploadBytes - bytes_pending_upload_);
|
| + throttle_state->SetInteger("bytes_pending_upload", bytes_pending_upload_);
|
| + throttle_state->SetInteger("scheduled_raster_task_count",
|
| + scheduled_raster_task_count_);
|
| + return throttle_state.PassAs<base::Value>();
|
| +}
|
| +
|
| } // namespace cc
|
|
|