| Index: cc/tiles/tile_manager.cc
|
| diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
|
| index 477025f3f80f9da5f0eb9304eafe787d7c398c64..9804da00fb6b93eeb4875904a5890d7bce320bde 100644
|
| --- a/cc/tiles/tile_manager.cc
|
| +++ b/cc/tiles/tile_manager.cc
|
| @@ -153,20 +153,91 @@ class RasterTaskImpl : public RasterTask {
|
| DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl);
|
| };
|
|
|
| -const char* TaskSetName(TaskSet task_set) {
|
| - switch (task_set) {
|
| - case TileManager::ALL:
|
| - return "ALL";
|
| - case TileManager::REQUIRED_FOR_ACTIVATION:
|
| - return "REQUIRED_FOR_ACTIVATION";
|
| - case TileManager::REQUIRED_FOR_DRAW:
|
| - return "REQUIRED_FOR_DRAW";
|
| +// Task priorities that make sure that the task set done tasks run before any
|
| +// other remaining tasks.
|
| +const size_t kRequiredForActivationDoneTaskPriority = 1u;
|
| +const size_t kRequiredForDrawDoneTaskPriority = 2u;
|
| +const size_t kAllDoneTaskPriority = 3u;
|
| +
|
| +// For correctness, |kTileTaskPriorityBase| must be greater than
|
| +// all task set done task priorities.
|
| +size_t kTileTaskPriorityBase = 10u;
|
| +
|
| +void InsertNodeForTask(TaskGraph* graph,
|
| + TileTask* task,
|
| + size_t priority,
|
| + size_t dependencies) {
|
| + DCHECK(std::find_if(graph->nodes.begin(), graph->nodes.end(),
|
| + [task](const TaskGraph::Node& node) {
|
| + return node.task == task;
|
| + }) == graph->nodes.end());
|
| + graph->nodes.push_back(TaskGraph::Node(task, priority, dependencies));
|
| +}
|
| +
|
| +void InsertNodesForRasterTask(TaskGraph* graph,
|
| + RasterTask* raster_task,
|
| + const ImageDecodeTask::Vector& decode_tasks,
|
| + size_t priority) {
|
| + size_t dependencies = 0u;
|
| +
|
| + // Insert image decode tasks.
|
| + for (ImageDecodeTask::Vector::const_iterator it = decode_tasks.begin();
|
| + it != decode_tasks.end(); ++it) {
|
| + ImageDecodeTask* decode_task = it->get();
|
| +
|
| + // Skip if already decoded.
|
| + if (decode_task->HasCompleted())
|
| + continue;
|
| +
|
| + dependencies++;
|
| +
|
| + // Add decode task if it doesn't already exists in graph.
|
| + TaskGraph::Node::Vector::iterator decode_it =
|
| + std::find_if(graph->nodes.begin(), graph->nodes.end(),
|
| + [decode_task](const TaskGraph::Node& node) {
|
| + return node.task == decode_task;
|
| + });
|
| + if (decode_it == graph->nodes.end())
|
| + InsertNodeForTask(graph, decode_task, priority, 0u);
|
| +
|
| + graph->edges.push_back(TaskGraph::Edge(decode_task, raster_task));
|
| }
|
|
|
| - NOTREACHED();
|
| - return "Invalid TaskSet";
|
| + InsertNodeForTask(graph, raster_task, priority, dependencies);
|
| }
|
|
|
| +class TaskSetFinishedTaskImpl : public TileTask {
|
| + public:
|
| + explicit TaskSetFinishedTaskImpl(
|
| + base::SequencedTaskRunner* task_runner,
|
| + const base::Closure& on_task_set_finished_callback)
|
| + : task_runner_(task_runner),
|
| + on_task_set_finished_callback_(on_task_set_finished_callback) {}
|
| +
|
| + // Overridden from Task:
|
| + void RunOnWorkerThread() override {
|
| + TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread");
|
| + TaskSetFinished();
|
| + }
|
| +
|
| + // Overridden from TileTask:
|
| + void ScheduleOnOriginThread(TileTaskClient* client) override {}
|
| + void CompleteOnOriginThread(TileTaskClient* client) override {}
|
| +
|
| + protected:
|
| + ~TaskSetFinishedTaskImpl() override {}
|
| +
|
| + void TaskSetFinished() {
|
| + task_runner_->PostTask(FROM_HERE, on_task_set_finished_callback_);
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<base::SequencedTaskRunner> task_runner_;
|
| + const base::Closure on_task_set_finished_callback_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TaskSetFinishedTaskImpl);
|
| +};
|
| +
|
| } // namespace
|
|
|
| RasterTaskCompletionStats::RasterTaskCompletionStats()
|
| @@ -216,7 +287,8 @@ TileManager::TileManager(
|
| base::Unretained(this))),
|
| has_scheduled_tile_tasks_(false),
|
| prepare_tiles_count_(0u),
|
| - next_tile_id_(0u) {}
|
| + next_tile_id_(0u),
|
| + task_set_finished_weak_ptr_factory_(this) {}
|
|
|
| TileManager::~TileManager() {
|
| FinishTasksAndCleanUp();
|
| @@ -228,13 +300,14 @@ void TileManager::FinishTasksAndCleanUp() {
|
|
|
| global_state_ = GlobalStateThatImpactsTilePriority();
|
|
|
| - TileTaskQueue empty;
|
| - tile_task_runner_->ScheduleTasks(&empty);
|
| - orphan_raster_tasks_.clear();
|
| -
|
| - // This should finish all pending tasks and release any uninitialized
|
| - // resources.
|
| + // This cancels tasks if possible, finishes pending tasks, and release any
|
| + // uninitialized resources.
|
| tile_task_runner_->Shutdown();
|
| +
|
| + // Now that all tasks have been finished, we can clear any
|
| + // |orphan_tasks_|.
|
| + orphan_tasks_.clear();
|
| +
|
| tile_task_runner_->CheckForCompletedTasks();
|
|
|
| FreeResourcesForReleasedTiles();
|
| @@ -244,6 +317,7 @@ void TileManager::FinishTasksAndCleanUp() {
|
| resource_pool_ = nullptr;
|
| more_tiles_need_prepare_check_notifier_.Cancel();
|
| signals_check_notifier_.Cancel();
|
| + task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
|
| }
|
|
|
| void TileManager::SetResources(ResourcePool* resource_pool,
|
| @@ -255,7 +329,6 @@ void TileManager::SetResources(ResourcePool* resource_pool,
|
| scheduled_raster_task_limit_ = scheduled_raster_task_limit;
|
| resource_pool_ = resource_pool;
|
| tile_task_runner_ = tile_task_runner;
|
| - tile_task_runner_->SetClient(this);
|
| }
|
|
|
| void TileManager::Release(Tile* tile) {
|
| @@ -285,44 +358,45 @@ void TileManager::CleanUpReleasedTiles() {
|
| released_tiles_.swap(tiles_to_retain);
|
| }
|
|
|
| -void TileManager::DidFinishRunningTileTasks(TaskSet task_set) {
|
| - TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
|
| - TaskSetName(task_set));
|
| +void TileManager::DidFinishRunningTileTasksRequiredForActivation() {
|
| + TRACE_EVENT0("cc",
|
| + "TileManager::DidFinishRunningTileTasksRequiredForActivation");
|
| + TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state",
|
| + ScheduledTasksStateAsValue());
|
| + signals_.ready_to_activate = true;
|
| + signals_check_notifier_.Schedule();
|
| +}
|
| +
|
| +void TileManager::DidFinishRunningTileTasksRequiredForDraw() {
|
| + TRACE_EVENT0("cc", "TileManager::DidFinishRunningTileTasksRequiredForDraw");
|
| + TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state",
|
| + ScheduledTasksStateAsValue());
|
| + signals_.ready_to_draw = true;
|
| + signals_check_notifier_.Schedule();
|
| +}
|
| +
|
| +void TileManager::DidFinishRunningAllTileTasks() {
|
| + TRACE_EVENT0("cc", "TileManager::DidFinishRunningAllTileTasks");
|
| + TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
|
| DCHECK(resource_pool_);
|
| DCHECK(tile_task_runner_);
|
|
|
| - switch (task_set) {
|
| - case ALL: {
|
| - has_scheduled_tile_tasks_ = false;
|
| + has_scheduled_tile_tasks_ = false;
|
|
|
| - bool memory_usage_above_limit = resource_pool_->memory_usage_bytes() >
|
| - global_state_.soft_memory_limit_in_bytes;
|
| -
|
| - if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
|
| - !memory_usage_above_limit) {
|
| - // TODO(ericrk): We should find a better way to safely handle re-entrant
|
| - // notifications than always having to schedule a new task.
|
| - // http://crbug.com/498439
|
| - signals_.all_tile_tasks_completed = true;
|
| - signals_check_notifier_.Schedule();
|
| - return;
|
| - }
|
| + bool memory_usage_above_limit = resource_pool_->memory_usage_bytes() >
|
| + global_state_.soft_memory_limit_in_bytes;
|
|
|
| - more_tiles_need_prepare_check_notifier_.Schedule();
|
| - return;
|
| - }
|
| - case REQUIRED_FOR_ACTIVATION:
|
| - signals_.ready_to_activate = true;
|
| - signals_check_notifier_.Schedule();
|
| - return;
|
| -
|
| - case REQUIRED_FOR_DRAW:
|
| - signals_.ready_to_draw = true;
|
| - signals_check_notifier_.Schedule();
|
| - return;
|
| + if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
|
| + !memory_usage_above_limit) {
|
| + // TODO(ericrk): We should find a better way to safely handle re-entrant
|
| + // notifications than always having to schedule a new task.
|
| + // http://crbug.com/498439
|
| + signals_.all_tile_tasks_completed = true;
|
| + signals_check_notifier_.Schedule();
|
| + return;
|
| }
|
|
|
| - NOTREACHED();
|
| + more_tiles_need_prepare_check_notifier_.Schedule();
|
| }
|
|
|
| bool TileManager::PrepareTiles(
|
| @@ -605,20 +679,41 @@ void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
|
|
|
| void TileManager::ScheduleTasks(
|
| const PrioritizedTileVector& tiles_that_need_to_be_rasterized) {
|
| - TRACE_EVENT1("cc",
|
| - "TileManager::ScheduleTasks",
|
| - "count",
|
| + TRACE_EVENT1("cc", "TileManager::ScheduleTasks", "count",
|
| tiles_that_need_to_be_rasterized.size());
|
|
|
| DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
|
|
|
| - raster_queue_.Reset();
|
| + if (!has_scheduled_tile_tasks_) {
|
| + TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
|
| + }
|
| +
|
| + // Cancel existing OnTaskSetFinished callbacks.
|
| + task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
|
|
|
| // Even when scheduling an empty set of tiles, the TTWP does some work, and
|
| // will always trigger a DidFinishRunningTileTasks notification. Because of
|
| // this we unconditionally set |has_scheduled_tile_tasks_| to true.
|
| has_scheduled_tile_tasks_ = true;
|
|
|
| + // Track the number of dependents for each *_done task.
|
| + size_t required_for_activate_count = 0;
|
| + size_t required_for_draw_count = 0;
|
| + size_t all_count = 0;
|
| +
|
| + size_t priority = kTileTaskPriorityBase;
|
| +
|
| + graph_.Reset();
|
| +
|
| + scoped_refptr<TileTask> required_for_activation_done_task =
|
| + CreateTaskSetFinishedTask(
|
| + &TileManager::DidFinishRunningTileTasksRequiredForActivation);
|
| + scoped_refptr<TileTask> required_for_draw_done_task =
|
| + CreateTaskSetFinishedTask(
|
| + &TileManager::DidFinishRunningTileTasksRequiredForDraw);
|
| + scoped_refptr<TileTask> all_done_task =
|
| + CreateTaskSetFinishedTask(&TileManager::DidFinishRunningAllTileTasks);
|
| +
|
| // Build a new task queue containing all task currently needed. Tasks
|
| // are added in order of priority, highest priority task first.
|
| for (auto& prioritized_tile : tiles_that_need_to_be_rasterized) {
|
| @@ -627,19 +722,40 @@ void TileManager::ScheduleTasks(
|
| DCHECK(tile->draw_info().requires_resource());
|
| DCHECK(!tile->draw_info().resource_);
|
|
|
| + if (!tile->raster_task_) {
|
| + tile->raster_task_ = CreateRasterTask(prioritized_tile);
|
| + }
|
| +
|
| + RasterTask* task = tile->raster_task_.get();
|
| + DCHECK(!task->HasCompleted());
|
| +
|
| if (!tile->raster_task_.get())
|
| tile->raster_task_ = CreateRasterTask(prioritized_tile);
|
|
|
| - TaskSetCollection task_sets;
|
| - if (tile->required_for_activation())
|
| - task_sets.set(REQUIRED_FOR_ACTIVATION);
|
| - if (tile->required_for_draw())
|
| - task_sets.set(REQUIRED_FOR_DRAW);
|
| - task_sets.set(ALL);
|
| - raster_queue_.items.push_back(
|
| - TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
|
| + if (tile->required_for_activation()) {
|
| + required_for_activate_count++;
|
| + graph_.edges.push_back(
|
| + TaskGraph::Edge(task, required_for_activation_done_task.get()));
|
| + }
|
| + if (tile->required_for_draw()) {
|
| + required_for_draw_count++;
|
| + graph_.edges.push_back(
|
| + TaskGraph::Edge(task, required_for_draw_done_task.get()));
|
| + }
|
| + all_count++;
|
| + graph_.edges.push_back(TaskGraph::Edge(task, all_done_task.get()));
|
| +
|
| + InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
|
| }
|
|
|
| + InsertNodeForTask(&graph_, required_for_activation_done_task.get(),
|
| + kRequiredForActivationDoneTaskPriority,
|
| + required_for_activate_count);
|
| + InsertNodeForTask(&graph_, required_for_draw_done_task.get(),
|
| + kRequiredForDrawDoneTaskPriority, required_for_draw_count);
|
| + InsertNodeForTask(&graph_, all_done_task.get(), kAllDoneTaskPriority,
|
| + all_count);
|
| +
|
| // We must reduce the amount of unused resoruces before calling
|
| // ScheduleTasks to prevent usage from rising above limits.
|
| resource_pool_->ReduceResourceUsage();
|
| @@ -647,14 +763,23 @@ void TileManager::ScheduleTasks(
|
| // Schedule running of |raster_queue_|. This replaces any previously
|
| // scheduled tasks and effectively cancels all tasks not present
|
| // in |raster_queue_|.
|
| - tile_task_runner_->ScheduleTasks(&raster_queue_);
|
| + tile_task_runner_->ScheduleTasks(&graph_);
|
|
|
| // It's now safe to clean up orphan tasks as raster worker pool is not
|
| // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
|
| // been called.
|
| - orphan_raster_tasks_.clear();
|
| + orphan_tasks_.clear();
|
| +
|
| + // It's also now safe to replace our *_done_task_ tasks.
|
| + required_for_activation_done_task_ =
|
| + std::move(required_for_activation_done_task);
|
| + required_for_draw_done_task_ = std::move(required_for_draw_done_task);
|
| + all_done_task_ = std::move(all_done_task);
|
|
|
| did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
|
| +
|
| + TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state",
|
| + ScheduledTasksStateAsValue());
|
| }
|
|
|
| scoped_refptr<RasterTask> TileManager::CreateRasterTask(
|
| @@ -709,7 +834,7 @@ void TileManager::OnRasterTaskCompleted(
|
|
|
| Tile* tile = tiles_[tile_id];
|
| DCHECK(tile->raster_task_.get());
|
| - orphan_raster_tasks_.push_back(tile->raster_task_);
|
| + orphan_tasks_.push_back(tile->raster_task_);
|
| tile->raster_task_ = nullptr;
|
|
|
| if (was_canceled) {
|
| @@ -773,7 +898,6 @@ ScopedTilePtr TileManager::CreateTile(const Tile::CreateInfo& info,
|
| void TileManager::SetTileTaskRunnerForTesting(
|
| TileTaskRunner* tile_task_runner) {
|
| tile_task_runner_ = tile_task_runner;
|
| - tile_task_runner_->SetClient(this);
|
| }
|
|
|
| bool TileManager::AreRequiredTilesReadyToDraw(
|
| @@ -947,9 +1071,32 @@ bool TileManager::DetermineResourceRequiresSwizzle(const Tile* tile) const {
|
| return tile_task_runner_->GetResourceRequiresSwizzle(!tile->is_opaque());
|
| }
|
|
|
| -TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
|
| +scoped_refptr<base::trace_event::ConvertableToTraceFormat>
|
| +TileManager::ScheduledTasksStateAsValue() const {
|
| + scoped_refptr<base::trace_event::TracedValue> state =
|
| + new base::trace_event::TracedValue();
|
| +
|
| + state->BeginDictionary("tasks_pending");
|
| + state->SetBoolean("ready_to_activate", signals_.ready_to_activate);
|
| + state->SetBoolean("ready_to_draw", signals_.ready_to_draw);
|
| + state->SetBoolean("all_tile_tasks_completed",
|
| + signals_.all_tile_tasks_completed);
|
| + state->EndDictionary();
|
| + return state;
|
| +}
|
| +
|
| +// Utility function that can be used to create a "Task set finished" task that
|
| +// posts |callback| to |task_runner| when run.
|
| +scoped_refptr<TileTask> TileManager::CreateTaskSetFinishedTask(
|
| + void (TileManager::*callback)()) {
|
| + return make_scoped_refptr(new TaskSetFinishedTaskImpl(
|
| + task_runner_.get(),
|
| + base::Bind(callback, task_set_finished_weak_ptr_factory_.GetWeakPtr())));
|
| }
|
|
|
| +TileManager::MemoryUsage::MemoryUsage()
|
| + : memory_bytes_(0), resource_count_(0) {}
|
| +
|
| TileManager::MemoryUsage::MemoryUsage(size_t memory_bytes,
|
| size_t resource_count)
|
| : memory_bytes_(static_cast<int64>(memory_bytes)),
|
|
|