• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <algorithm>
8 
9 #include "base/atomic_sequence_num.h"
10 #include "base/debug/trace_event_synthetic_delay.h"
11 #include "base/lazy_instance.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/threading/simple_thread.h"
14 #include "base/threading/thread_local.h"
15 #include "cc/base/scoped_ptr_deque.h"
16 
17 namespace cc {
18 namespace {
19 
20 // Synthetic delay for raster tasks that are required for activation. Global to
21 // avoid static initializer on critical path.
22 struct RasterRequiredForActivationSyntheticDelayInitializer {
RasterRequiredForActivationSyntheticDelayInitializercc::__anon69c63fa50111::RasterRequiredForActivationSyntheticDelayInitializer23   RasterRequiredForActivationSyntheticDelayInitializer()
24       : delay(base::debug::TraceEventSyntheticDelay::Lookup(
25             "cc.RasterRequiredForActivation")) {}
26   base::debug::TraceEventSyntheticDelay* delay;
27 };
28 static base::LazyInstance<RasterRequiredForActivationSyntheticDelayInitializer>
29     g_raster_required_for_activation_delay = LAZY_INSTANCE_INITIALIZER;
30 
31 class RasterTaskGraphRunner : public TaskGraphRunner,
32                               public base::DelegateSimpleThread::Delegate {
33  public:
RasterTaskGraphRunner()34   RasterTaskGraphRunner() {
35     size_t num_threads = RasterWorkerPool::GetNumRasterThreads();
36     while (workers_.size() < num_threads) {
37       scoped_ptr<base::DelegateSimpleThread> worker =
38           make_scoped_ptr(new base::DelegateSimpleThread(
39               this,
40               base::StringPrintf("CompositorRasterWorker%u",
41                                  static_cast<unsigned>(workers_.size() + 1))
42                   .c_str()));
43       worker->Start();
44 #if defined(OS_ANDROID) || defined(OS_LINUX)
45       worker->SetThreadPriority(base::kThreadPriority_Background);
46 #endif
47       workers_.push_back(worker.Pass());
48     }
49   }
50 
~RasterTaskGraphRunner()51   virtual ~RasterTaskGraphRunner() { NOTREACHED(); }
52 
GetPictureCloneIndexForCurrentThread()53   size_t GetPictureCloneIndexForCurrentThread() {
54     // Use index 0 if called on non-raster thread.
55     ThreadLocalState* thread_local_state = current_tls_.Get();
56     return thread_local_state ? current_tls_.Get()->picture_clone_index : 0;
57   }
58 
59  private:
60   struct ThreadLocalState {
ThreadLocalStatecc::__anon69c63fa50111::RasterTaskGraphRunner::ThreadLocalState61     explicit ThreadLocalState(size_t picture_clone_index)
62         : picture_clone_index(picture_clone_index) {}
63 
64     size_t picture_clone_index;
65   };
66 
67   // Overridden from base::DelegateSimpleThread::Delegate:
Run()68   virtual void Run() OVERRIDE {
69     // Use picture clone index 0..num_threads.
70     int picture_clone_index = picture_clone_index_sequence_.GetNext();
71     DCHECK_LE(0, picture_clone_index);
72     DCHECK_GT(RasterWorkerPool::GetNumRasterThreads(), picture_clone_index);
73     current_tls_.Set(new ThreadLocalState(picture_clone_index));
74 
75     TaskGraphRunner::Run();
76   }
77 
78   ScopedPtrDeque<base::DelegateSimpleThread> workers_;
79   base::AtomicSequenceNumber picture_clone_index_sequence_;
80   base::ThreadLocalPointer<ThreadLocalState> current_tls_;
81 };
82 
83 base::LazyInstance<RasterTaskGraphRunner>::Leaky g_task_graph_runner =
84     LAZY_INSTANCE_INITIALIZER;
85 
86 const int kDefaultNumRasterThreads = 1;
87 
88 int g_num_raster_threads = 0;
89 
90 class RasterFinishedTaskImpl : public RasterizerTask {
91  public:
RasterFinishedTaskImpl(base::SequencedTaskRunner * task_runner,const base::Closure & on_raster_finished_callback)92   explicit RasterFinishedTaskImpl(
93       base::SequencedTaskRunner* task_runner,
94       const base::Closure& on_raster_finished_callback)
95       : task_runner_(task_runner),
96         on_raster_finished_callback_(on_raster_finished_callback) {}
97 
98   // Overridden from Task:
RunOnWorkerThread()99   virtual void RunOnWorkerThread() OVERRIDE {
100     TRACE_EVENT0("cc", "RasterFinishedTaskImpl::RunOnWorkerThread");
101     RasterFinished();
102   }
103 
104   // Overridden from RasterizerTask:
ScheduleOnOriginThread(RasterizerTaskClient * client)105   virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
CompleteOnOriginThread(RasterizerTaskClient * client)106   virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
RunReplyOnOriginThread()107   virtual void RunReplyOnOriginThread() OVERRIDE {}
108 
109  protected:
~RasterFinishedTaskImpl()110   virtual ~RasterFinishedTaskImpl() {}
111 
RasterFinished()112   void RasterFinished() {
113     task_runner_->PostTask(FROM_HERE, on_raster_finished_callback_);
114   }
115 
116  private:
117   scoped_refptr<base::SequencedTaskRunner> task_runner_;
118   const base::Closure on_raster_finished_callback_;
119 
120   DISALLOW_COPY_AND_ASSIGN(RasterFinishedTaskImpl);
121 };
122 
123 class RasterRequiredForActivationFinishedTaskImpl
124     : public RasterFinishedTaskImpl {
125  public:
RasterRequiredForActivationFinishedTaskImpl(base::SequencedTaskRunner * task_runner,const base::Closure & on_raster_finished_callback,size_t tasks_required_for_activation_count)126   RasterRequiredForActivationFinishedTaskImpl(
127       base::SequencedTaskRunner* task_runner,
128       const base::Closure& on_raster_finished_callback,
129       size_t tasks_required_for_activation_count)
130       : RasterFinishedTaskImpl(task_runner, on_raster_finished_callback),
131         tasks_required_for_activation_count_(
132             tasks_required_for_activation_count) {
133     if (tasks_required_for_activation_count_) {
134       g_raster_required_for_activation_delay.Get().delay->BeginParallel(
135           &activation_delay_end_time_);
136     }
137   }
138 
139   // Overridden from Task:
RunOnWorkerThread()140   virtual void RunOnWorkerThread() OVERRIDE {
141     TRACE_EVENT0(
142         "cc", "RasterRequiredForActivationFinishedTaskImpl::RunOnWorkerThread");
143 
144     if (tasks_required_for_activation_count_) {
145       g_raster_required_for_activation_delay.Get().delay->EndParallel(
146           activation_delay_end_time_);
147     }
148     RasterFinished();
149   }
150 
151  private:
~RasterRequiredForActivationFinishedTaskImpl()152   virtual ~RasterRequiredForActivationFinishedTaskImpl() {}
153 
154   base::TimeTicks activation_delay_end_time_;
155   const size_t tasks_required_for_activation_count_;
156 
157   DISALLOW_COPY_AND_ASSIGN(RasterRequiredForActivationFinishedTaskImpl);
158 };
159 
160 }  // namespace
161 
162 // This allows an external rasterize on-demand system to run raster tasks
163 // with highest priority using the same task graph runner instance.
164 unsigned RasterWorkerPool::kOnDemandRasterTaskPriority = 0u;
165 // This allows a micro benchmark system to run tasks with highest priority,
166 // since it should finish as quickly as possible.
167 unsigned RasterWorkerPool::kBenchmarkRasterTaskPriority = 0u;
168 // Task priorities that make sure raster finished tasks run before any
169 // remaining raster tasks.
170 unsigned RasterWorkerPool::kRasterFinishedTaskPriority = 2u;
171 unsigned RasterWorkerPool::kRasterRequiredForActivationFinishedTaskPriority =
172     1u;
173 unsigned RasterWorkerPool::kRasterTaskPriorityBase = 3u;
174 
RasterWorkerPool()175 RasterWorkerPool::RasterWorkerPool() {}
176 
~RasterWorkerPool()177 RasterWorkerPool::~RasterWorkerPool() {}
178 
179 // static
SetNumRasterThreads(int num_threads)180 void RasterWorkerPool::SetNumRasterThreads(int num_threads) {
181   DCHECK_LT(0, num_threads);
182   DCHECK_EQ(0, g_num_raster_threads);
183 
184   g_num_raster_threads = num_threads;
185 }
186 
187 // static
GetNumRasterThreads()188 int RasterWorkerPool::GetNumRasterThreads() {
189   if (!g_num_raster_threads)
190     g_num_raster_threads = kDefaultNumRasterThreads;
191 
192   return g_num_raster_threads;
193 }
194 
195 // static
GetTaskGraphRunner()196 TaskGraphRunner* RasterWorkerPool::GetTaskGraphRunner() {
197   return g_task_graph_runner.Pointer();
198 }
199 
200 // static
GetPictureCloneIndexForCurrentThread()201 size_t RasterWorkerPool::GetPictureCloneIndexForCurrentThread() {
202   return g_task_graph_runner.Pointer()->GetPictureCloneIndexForCurrentThread();
203 }
204 
205 // static
CreateRasterFinishedTask(base::SequencedTaskRunner * task_runner,const base::Closure & on_raster_finished_callback)206 scoped_refptr<RasterizerTask> RasterWorkerPool::CreateRasterFinishedTask(
207     base::SequencedTaskRunner* task_runner,
208     const base::Closure& on_raster_finished_callback) {
209   return make_scoped_refptr(
210       new RasterFinishedTaskImpl(task_runner, on_raster_finished_callback));
211 }
212 
213 // static
214 scoped_refptr<RasterizerTask>
CreateRasterRequiredForActivationFinishedTask(size_t tasks_required_for_activation_count,base::SequencedTaskRunner * task_runner,const base::Closure & on_raster_finished_callback)215 RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask(
216     size_t tasks_required_for_activation_count,
217     base::SequencedTaskRunner* task_runner,
218     const base::Closure& on_raster_finished_callback) {
219   return make_scoped_refptr(new RasterRequiredForActivationFinishedTaskImpl(
220       task_runner,
221       on_raster_finished_callback,
222       tasks_required_for_activation_count));
223 }
224 
225 // static
ScheduleTasksOnOriginThread(RasterizerTaskClient * client,TaskGraph * graph)226 void RasterWorkerPool::ScheduleTasksOnOriginThread(RasterizerTaskClient* client,
227                                                    TaskGraph* graph) {
228   TRACE_EVENT0("cc", "Rasterizer::ScheduleTasksOnOriginThread");
229 
230   for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
231        it != graph->nodes.end();
232        ++it) {
233     TaskGraph::Node& node = *it;
234     RasterizerTask* task = static_cast<RasterizerTask*>(node.task);
235 
236     if (!task->HasBeenScheduled()) {
237       task->WillSchedule();
238       task->ScheduleOnOriginThread(client);
239       task->DidSchedule();
240     }
241   }
242 }
243 
244 // static
InsertNodeForTask(TaskGraph * graph,RasterizerTask * task,unsigned priority,size_t dependencies)245 void RasterWorkerPool::InsertNodeForTask(TaskGraph* graph,
246                                          RasterizerTask* task,
247                                          unsigned priority,
248                                          size_t dependencies) {
249   DCHECK(std::find_if(graph->nodes.begin(),
250                       graph->nodes.end(),
251                       TaskGraph::Node::TaskComparator(task)) ==
252          graph->nodes.end());
253   graph->nodes.push_back(TaskGraph::Node(task, priority, dependencies));
254 }
255 
256 // static
InsertNodesForRasterTask(TaskGraph * graph,RasterTask * raster_task,const ImageDecodeTask::Vector & decode_tasks,unsigned priority)257 void RasterWorkerPool::InsertNodesForRasterTask(
258     TaskGraph* graph,
259     RasterTask* raster_task,
260     const ImageDecodeTask::Vector& decode_tasks,
261     unsigned priority) {
262   size_t dependencies = 0u;
263 
264   // Insert image decode tasks.
265   for (ImageDecodeTask::Vector::const_iterator it = decode_tasks.begin();
266        it != decode_tasks.end();
267        ++it) {
268     ImageDecodeTask* decode_task = it->get();
269 
270     // Skip if already decoded.
271     if (decode_task->HasCompleted())
272       continue;
273 
274     dependencies++;
275 
276     // Add decode task if it doesn't already exists in graph.
277     TaskGraph::Node::Vector::iterator decode_it =
278         std::find_if(graph->nodes.begin(),
279                      graph->nodes.end(),
280                      TaskGraph::Node::TaskComparator(decode_task));
281     if (decode_it == graph->nodes.end())
282       InsertNodeForTask(graph, decode_task, priority, 0u);
283 
284     graph->edges.push_back(TaskGraph::Edge(decode_task, raster_task));
285   }
286 
287   InsertNodeForTask(graph, raster_task, priority, dependencies);
288 }
289 
290 }  // namespace cc
291