| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #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/SkBitmapDevice.h" |
| |
| #if defined(OS_ANDROID) |
| #include "base/android/sys_utils.h" |
| #endif |
| |
| namespace cc { |
| |
| namespace { |
| |
| class PixelBufferWorkerPoolTaskImpl : public internal::WorkerPoolTask { |
| public: |
| typedef base::Callback<void(bool was_canceled, bool needs_upload)> Reply; |
| |
| PixelBufferWorkerPoolTaskImpl(internal::RasterWorkerPoolTask* task, |
| uint8_t* buffer, |
| const Reply& reply) |
| : task_(task), |
| buffer_(buffer), |
| reply_(reply), |
| needs_upload_(false) { |
| } |
| |
| // Overridden from internal::WorkerPoolTask: |
| virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE { |
| // |buffer_| can be NULL in lost context situations. |
| if (!buffer_) { |
| // |needs_upload_| still needs to be true as task has not |
| // been canceled. |
| needs_upload_ = true; |
| return; |
| } |
| needs_upload_ = task_->RunOnWorkerThread(thread_index, |
| buffer_, |
| task_->resource()->size(), |
| 0); |
| } |
| virtual void CompleteOnOriginThread() OVERRIDE { |
| // |needs_upload_| must be be false if task didn't run. |
| DCHECK(HasFinishedRunning() || !needs_upload_); |
| reply_.Run(!HasFinishedRunning(), needs_upload_); |
| } |
| |
| private: |
| virtual ~PixelBufferWorkerPoolTaskImpl() {} |
| |
| scoped_refptr<internal::RasterWorkerPoolTask> task_; |
| uint8_t* buffer_; |
| const Reply reply_; |
| bool needs_upload_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PixelBufferWorkerPoolTaskImpl); |
| }; |
| |
| const int kCheckForCompletedRasterTasksDelayMs = 6; |
| |
| 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); |
| } |
| } |
| |
| // Only used as std::find_if predicate for DCHECKs. |
| bool WasCanceled(const internal::RasterWorkerPoolTask* task) { |
| return task->WasCanceled(); |
| } |
| |
| } // namespace |
| |
| PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool( |
| ResourceProvider* resource_provider, |
| size_t num_threads, |
| size_t max_transfer_buffer_usage_bytes) |
| : RasterWorkerPool(resource_provider, num_threads), |
| shutdown_(false), |
| scheduled_raster_task_count_(0), |
| bytes_pending_upload_(0), |
| max_bytes_pending_upload_(max_transfer_buffer_usage_bytes), |
| 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() { |
| DCHECK(shutdown_); |
| DCHECK(!check_for_completed_raster_tasks_pending_); |
| DCHECK_EQ(0u, pixel_buffer_tasks_.size()); |
| DCHECK_EQ(0u, tasks_with_pending_upload_.size()); |
| DCHECK_EQ(0u, completed_tasks_.size()); |
| } |
| |
| void PixelBufferRasterWorkerPool::Shutdown() { |
| shutdown_ = true; |
| RasterWorkerPool::Shutdown(); |
| 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; |
| internal::WorkerPoolTask* pixel_buffer_task = it->second.get(); |
| |
| // All inactive tasks needs to be canceled. |
| if (!pixel_buffer_task && !task->HasFinishedRunning()) { |
| task->DidRun(true); |
| completed_tasks_.push_back(task); |
| } |
| } |
| DCHECK_EQ(completed_tasks_.size(), pixel_buffer_tasks_.size()); |
| } |
| |
| void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) { |
| TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleTasks"); |
| |
| 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; |
| |
| tasks_required_for_activation_.clear(); |
| |
| // Build new pixel buffer task set. |
| TaskMap new_pixel_buffer_tasks; |
| for (RasterTaskVector::const_iterator it = raster_tasks().begin(); |
| it != raster_tasks().end(); ++it) { |
| internal::RasterWorkerPoolTask* task = it->get(); |
| DCHECK(new_pixel_buffer_tasks.find(task) == new_pixel_buffer_tasks.end()); |
| DCHECK(!task->HasCompleted()); |
| DCHECK(!task->WasCanceled()); |
| |
| new_pixel_buffer_tasks[task] = pixel_buffer_tasks_[task]; |
| pixel_buffer_tasks_.erase(task); |
| |
| if (IsRasterTaskRequiredForActivation(task)) |
| tasks_required_for_activation_.insert(task); |
| } |
| |
| // Transfer remaining pixel buffer tasks to |new_pixel_buffer_tasks| |
| // and cancel all remaining inactive tasks. |
| for (TaskMap::iterator it = pixel_buffer_tasks_.begin(); |
| it != pixel_buffer_tasks_.end(); ++it) { |
| internal::RasterWorkerPoolTask* task = it->first; |
| internal::WorkerPoolTask* pixel_buffer_task = it->second.get(); |
| |
| // Move task to |new_pixel_buffer_tasks| |
| new_pixel_buffer_tasks[task] = pixel_buffer_task; |
| |
| // Inactive task can be canceled. |
| if (!pixel_buffer_task && !task->HasFinishedRunning()) { |
| task->DidRun(true); |
| DCHECK(std::find(completed_tasks_.begin(), |
| completed_tasks_.end(), |
| task) == completed_tasks_.end()); |
| completed_tasks_.push_back(task); |
| } else if (IsRasterTaskRequiredForActivation(task)) { |
| tasks_required_for_activation_.insert(task); |
| } |
| } |
| |
| // |tasks_required_for_activation_| contains all tasks that need to |
| // complete before we can send a "ready to activate" signal. Tasks |
| // that have already completed should not be part of this set. |
| for (TaskDeque::const_iterator it = completed_tasks_.begin(); |
| it != completed_tasks_.end() && !tasks_required_for_activation_.empty(); |
| ++it) { |
| tasks_required_for_activation_.erase(*it); |
| } |
| |
| pixel_buffer_tasks_.swap(new_pixel_buffer_tasks); |
| |
| // 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_STEP_INTO1( |
| "cc", "ScheduledTasks", this, StateName(), |
| "state", TracedValue::FromValue(StateAsValue().release())); |
| } |
| |
| ResourceFormat PixelBufferRasterWorkerPool::GetResourceFormat() const { |
| return resource_provider()->memory_efficient_texture_format(); |
| } |
| |
| void PixelBufferRasterWorkerPool::CheckForCompletedTasks() { |
| TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::CheckForCompletedTasks"); |
| |
| RasterWorkerPool::CheckForCompletedTasks(); |
| CheckForCompletedUploads(); |
| FlushUploads(); |
| |
| 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); |
| |
| task->WillComplete(); |
| task->CompleteOnOriginThread(); |
| task->DidComplete(); |
| |
| completed_tasks.pop_front(); |
| } |
| } |
| |
| void PixelBufferRasterWorkerPool::OnRasterTasksFinished() { |
| // |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(); |
| } |
| |
| void PixelBufferRasterWorkerPool::FlushUploads() { |
| if (!has_performed_uploads_since_last_flush_) |
| return; |
| |
| resource_provider()->ShallowFlushIfSupported(); |
| has_performed_uploads_since_last_flush_ = false; |
| } |
| |
| void PixelBufferRasterWorkerPool::CheckForCompletedUploads() { |
| TaskDeque tasks_with_completed_uploads; |
| |
| // First check if any have completed. |
| while (!tasks_with_pending_upload_.empty()) { |
| internal::RasterWorkerPoolTask* task = |
| tasks_with_pending_upload_.front().get(); |
| |
| // Uploads complete in the order they are issued. |
| if (!resource_provider()->DidSetPixelsComplete(task->resource()->id())) |
| break; |
| |
| tasks_with_completed_uploads.push_back(task); |
| tasks_with_pending_upload_.pop_front(); |
| } |
| |
| DCHECK(client()); |
| bool should_force_some_uploads_to_complete = |
| shutdown_ || client()->ShouldForceTasksRequiredForActivationToComplete(); |
| |
| if (should_force_some_uploads_to_complete) { |
| TaskDeque tasks_with_uploads_to_force; |
| TaskDeque::iterator it = tasks_with_pending_upload_.begin(); |
| while (it != tasks_with_pending_upload_.end()) { |
| internal::RasterWorkerPoolTask* task = it->get(); |
| DCHECK(pixel_buffer_tasks_.find(task) != pixel_buffer_tasks_.end()); |
| |
| // Force all uploads required for activation to complete. |
| // During shutdown, force all pending uploads to complete. |
| if (shutdown_ || IsRasterTaskRequiredForActivation(task)) { |
| tasks_with_uploads_to_force.push_back(task); |
| tasks_with_completed_uploads.push_back(task); |
| it = tasks_with_pending_upload_.erase(it); |
| continue; |
| } |
| |
| ++it; |
| } |
| |
| // Force uploads in reverse order. Since forcing can cause a wait on |
| // all previous uploads, we would rather wait only once downstream. |
| for (TaskDeque::reverse_iterator it = tasks_with_uploads_to_force.rbegin(); |
| it != tasks_with_uploads_to_force.rend(); |
| ++it) { |
| resource_provider()->ForceSetPixelsToComplete((*it)->resource()->id()); |
| has_performed_uploads_since_last_flush_ = true; |
| } |
| } |
| |
| // Release shared memory and move tasks with completed uploads |
| // to |completed_tasks_|. |
| while (!tasks_with_completed_uploads.empty()) { |
| internal::RasterWorkerPoolTask* task = |
| tasks_with_completed_uploads.front().get(); |
| |
| // It's now safe to release the pixel buffer and the shared memory. |
| resource_provider()->ReleasePixelBuffer(task->resource()->id()); |
| |
| bytes_pending_upload_ -= task->resource()->bytes(); |
| |
| task->DidRun(false); |
| |
| DCHECK(std::find(completed_tasks_.begin(), |
| completed_tasks_.end(), |
| task) == completed_tasks_.end()); |
| completed_tasks_.push_back(task); |
| |
| tasks_required_for_activation_.erase(task); |
| |
| tasks_with_completed_uploads.pop_front(); |
| } |
| } |
| |
| void PixelBufferRasterWorkerPool::ScheduleCheckForCompletedRasterTasks() { |
| if (check_for_completed_raster_tasks_pending_) |
| return; |
| |
| check_for_completed_raster_tasks_callback_.Reset( |
| base::Bind(&PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks, |
| base::Unretained(this))); |
| base::MessageLoopProxy::current()->PostDelayedTask( |
| FROM_HERE, |
| check_for_completed_raster_tasks_callback_.callback(), |
| base::TimeDelta::FromMilliseconds(kCheckForCompletedRasterTasksDelayMs)); |
| check_for_completed_raster_tasks_pending_ = true; |
| } |
| |
| 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; |
| |
| RasterWorkerPool::CheckForCompletedTasks(); |
| CheckForCompletedUploads(); |
| FlushUploads(); |
| |
| // 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; |
| |
| scheduled_raster_task_count_ = 0; |
| if (PendingRasterTaskCount()) |
| ScheduleMoreTasks(); |
| |
| TRACE_EVENT_ASYNC_STEP_INTO1( |
| "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) { |
| DCHECK(std::find_if(raster_tasks_required_for_activation().begin(), |
| raster_tasks_required_for_activation().end(), |
| WasCanceled) == |
| raster_tasks_required_for_activation().end()); |
| client()->DidFinishRunningTasksRequiredForActivation(); |
| } |
| if (will_notify_client_that_no_tasks_are_pending) { |
| TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); |
| DCHECK(!HasPendingTasksRequiredForActivation()); |
| client()->DidFinishRunningTasks(); |
| } |
| } |
| |
| 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_; |
| |
| for (RasterTaskVector::const_iterator it = raster_tasks().begin(); |
| it != raster_tasks().end(); ++it) { |
| internal::RasterWorkerPoolTask* task = it->get(); |
| |
| // |pixel_buffer_tasks_| contains all tasks that have not yet completed. |
| TaskMap::iterator pixel_buffer_it = pixel_buffer_tasks_.find(task); |
| if (pixel_buffer_it == pixel_buffer_tasks_.end()) |
| continue; |
| |
| // HasFinishedRunning() will return true when set pixels has completed. |
| if (task->HasFinishedRunning()) { |
| DCHECK(std::find(completed_tasks_.begin(), |
| completed_tasks_.end(), |
| task) != completed_tasks_.end()); |
| continue; |
| } |
| |
| // All raster tasks need to be throttled by bytes of pending uploads. |
| size_t new_bytes_pending_upload = bytes_pending_upload; |
| new_bytes_pending_upload += task->resource()->bytes(); |
| if (new_bytes_pending_upload > max_bytes_pending_upload_) |
| break; |
| |
| internal::WorkerPoolTask* pixel_buffer_task = pixel_buffer_it->second.get(); |
| |
| // If raster has finished, just update |bytes_pending_upload|. |
| if (pixel_buffer_task && pixel_buffer_task->HasCompleted()) { |
| bytes_pending_upload = new_bytes_pending_upload; |
| continue; |
| } |
| |
| // 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 |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) { |
| tasks[type].container().push_back( |
| CreateGraphNodeForRasterTask(pixel_buffer_task, |
| task->dependencies(), |
| priority++, |
| &graph)); |
| continue; |
| } |
| |
| // Request a pixel buffer. This will reserve shared memory. |
| resource_provider()->AcquirePixelBuffer(task->resource()->id()); |
| |
| // MapPixelBuffer() returns NULL if context was lost at the time |
| // AcquirePixelBuffer() was called. For simplicity we still post |
| // a raster task that is essentially a noop in these situations. |
| uint8* buffer = resource_provider()->MapPixelBuffer( |
| task->resource()->id()); |
| |
| scoped_refptr<internal::WorkerPoolTask> new_pixel_buffer_task( |
| new PixelBufferWorkerPoolTaskImpl( |
| task, |
| buffer, |
| base::Bind(&PixelBufferRasterWorkerPool::OnRasterTaskCompleted, |
| base::Unretained(this), |
| make_scoped_refptr(task)))); |
| pixel_buffer_tasks_[task] = new_pixel_buffer_task; |
| tasks[type].container().push_back( |
| CreateGraphNodeForRasterTask(new_pixel_buffer_task.get(), |
| task->dependencies(), |
| priority++, |
| &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()); |
| } |
| |
| 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( |
| scoped_refptr<internal::RasterWorkerPoolTask> task, |
| bool was_canceled, |
| bool needs_upload) { |
| TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc"), |
| "PixelBufferRasterWorkerPool::OnRasterTaskCompleted", |
| "was_canceled", was_canceled, |
| "needs_upload", needs_upload); |
| |
| DCHECK(pixel_buffer_tasks_.find(task.get()) != pixel_buffer_tasks_.end()); |
| |
| // Balanced with MapPixelBuffer() call in ScheduleMoreTasks(). |
| resource_provider()->UnmapPixelBuffer(task->resource()->id()); |
| |
| if (!needs_upload) { |
| resource_provider()->ReleasePixelBuffer(task->resource()->id()); |
| |
| if (was_canceled) { |
| // When priorites change, a raster task can be canceled as a result of |
| // no longer being of high enough priority to fit in our throttled |
| // raster task budget. The task has not yet completed in this case. |
| RasterTaskVector::const_iterator it = std::find(raster_tasks().begin(), |
| raster_tasks().end(), |
| task); |
| if (it != raster_tasks().end()) { |
| pixel_buffer_tasks_[task.get()] = NULL; |
| return; |
| } |
| } |
| |
| task->DidRun(was_canceled); |
| DCHECK(std::find(completed_tasks_.begin(), |
| completed_tasks_.end(), |
| task) == completed_tasks_.end()); |
| completed_tasks_.push_back(task); |
| tasks_required_for_activation_.erase(task); |
| return; |
| } |
| |
| DCHECK(!was_canceled); |
| |
| resource_provider()->BeginSetPixels(task->resource()->id()); |
| has_performed_uploads_since_last_flush_ = true; |
| |
| bytes_pending_upload_ += task->resource()->bytes(); |
| 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", |
| max_bytes_pending_upload_ - 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 |