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/debug/trace_event.h"
10#include "base/lazy_instance.h"
11#include "base/strings/stringprintf.h"
12#include "base/threading/simple_thread.h"
13#include "cc/base/scoped_ptr_deque.h"
14
15namespace cc {
16namespace {
17
18class RasterTaskGraphRunner : public TaskGraphRunner,
19                              public base::DelegateSimpleThread::Delegate {
20 public:
21  RasterTaskGraphRunner() {
22    size_t num_threads = RasterWorkerPool::GetNumRasterThreads();
23    while (workers_.size() < num_threads) {
24      scoped_ptr<base::DelegateSimpleThread> worker =
25          make_scoped_ptr(new base::DelegateSimpleThread(
26              this,
27              base::StringPrintf("CompositorRasterWorker%u",
28                                 static_cast<unsigned>(workers_.size() + 1))
29                  .c_str()));
30      worker->Start();
31#if defined(OS_ANDROID) || defined(OS_LINUX)
32      worker->SetThreadPriority(base::kThreadPriority_Background);
33#endif
34      workers_.push_back(worker.Pass());
35    }
36  }
37
38  virtual ~RasterTaskGraphRunner() { NOTREACHED(); }
39
40 private:
41  // Overridden from base::DelegateSimpleThread::Delegate:
42  virtual void Run() OVERRIDE {
43    TaskGraphRunner::Run();
44  }
45
46  ScopedPtrDeque<base::DelegateSimpleThread> workers_;
47};
48
49base::LazyInstance<RasterTaskGraphRunner>::Leaky g_task_graph_runner =
50    LAZY_INSTANCE_INITIALIZER;
51
52const int kDefaultNumRasterThreads = 1;
53
54int g_num_raster_threads = 0;
55
56class RasterFinishedTaskImpl : public RasterizerTask {
57 public:
58  explicit RasterFinishedTaskImpl(
59      base::SequencedTaskRunner* task_runner,
60      const base::Closure& on_raster_finished_callback)
61      : task_runner_(task_runner),
62        on_raster_finished_callback_(on_raster_finished_callback) {}
63
64  // Overridden from Task:
65  virtual void RunOnWorkerThread() OVERRIDE {
66    TRACE_EVENT0("cc", "RasterFinishedTaskImpl::RunOnWorkerThread");
67    RasterFinished();
68  }
69
70  // Overridden from RasterizerTask:
71  virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
72  virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
73  virtual void RunReplyOnOriginThread() OVERRIDE {}
74
75 protected:
76  virtual ~RasterFinishedTaskImpl() {}
77
78  void RasterFinished() {
79    task_runner_->PostTask(FROM_HERE, on_raster_finished_callback_);
80  }
81
82 private:
83  scoped_refptr<base::SequencedTaskRunner> task_runner_;
84  const base::Closure on_raster_finished_callback_;
85
86  DISALLOW_COPY_AND_ASSIGN(RasterFinishedTaskImpl);
87};
88
89}  // namespace
90
91// This allows a micro benchmark system to run tasks with highest priority,
92// since it should finish as quickly as possible.
93unsigned RasterWorkerPool::kBenchmarkRasterTaskPriority = 0u;
94// Task priorities that make sure raster finished tasks run before any
95// remaining raster tasks.
96unsigned RasterWorkerPool::kRasterFinishedTaskPriority = 1u;
97unsigned RasterWorkerPool::kRasterTaskPriorityBase = 2u;
98
99RasterWorkerPool::RasterWorkerPool() {}
100
101RasterWorkerPool::~RasterWorkerPool() {}
102
103// static
104void RasterWorkerPool::SetNumRasterThreads(int num_threads) {
105  DCHECK_LT(0, num_threads);
106  DCHECK_EQ(0, g_num_raster_threads);
107
108  g_num_raster_threads = num_threads;
109}
110
111// static
112int RasterWorkerPool::GetNumRasterThreads() {
113  if (!g_num_raster_threads)
114    g_num_raster_threads = kDefaultNumRasterThreads;
115
116  return g_num_raster_threads;
117}
118
119// static
120TaskGraphRunner* RasterWorkerPool::GetTaskGraphRunner() {
121  return g_task_graph_runner.Pointer();
122}
123
124// static
125scoped_refptr<RasterizerTask> RasterWorkerPool::CreateRasterFinishedTask(
126    base::SequencedTaskRunner* task_runner,
127    const base::Closure& on_raster_finished_callback) {
128  return make_scoped_refptr(
129      new RasterFinishedTaskImpl(task_runner, on_raster_finished_callback));
130}
131
132// static
133void RasterWorkerPool::ScheduleTasksOnOriginThread(RasterizerTaskClient* client,
134                                                   TaskGraph* graph) {
135  TRACE_EVENT0("cc", "Rasterizer::ScheduleTasksOnOriginThread");
136
137  for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
138       it != graph->nodes.end();
139       ++it) {
140    TaskGraph::Node& node = *it;
141    RasterizerTask* task = static_cast<RasterizerTask*>(node.task);
142
143    if (!task->HasBeenScheduled()) {
144      task->WillSchedule();
145      task->ScheduleOnOriginThread(client);
146      task->DidSchedule();
147    }
148  }
149}
150
151// static
152void RasterWorkerPool::InsertNodeForTask(TaskGraph* graph,
153                                         RasterizerTask* task,
154                                         unsigned priority,
155                                         size_t dependencies) {
156  DCHECK(std::find_if(graph->nodes.begin(),
157                      graph->nodes.end(),
158                      TaskGraph::Node::TaskComparator(task)) ==
159         graph->nodes.end());
160  graph->nodes.push_back(TaskGraph::Node(task, priority, dependencies));
161}
162
163// static
164void RasterWorkerPool::InsertNodesForRasterTask(
165    TaskGraph* graph,
166    RasterTask* raster_task,
167    const ImageDecodeTask::Vector& decode_tasks,
168    unsigned priority) {
169  size_t dependencies = 0u;
170
171  // Insert image decode tasks.
172  for (ImageDecodeTask::Vector::const_iterator it = decode_tasks.begin();
173       it != decode_tasks.end();
174       ++it) {
175    ImageDecodeTask* decode_task = it->get();
176
177    // Skip if already decoded.
178    if (decode_task->HasCompleted())
179      continue;
180
181    dependencies++;
182
183    // Add decode task if it doesn't already exists in graph.
184    TaskGraph::Node::Vector::iterator decode_it =
185        std::find_if(graph->nodes.begin(),
186                     graph->nodes.end(),
187                     TaskGraph::Node::TaskComparator(decode_task));
188    if (decode_it == graph->nodes.end())
189      InsertNodeForTask(graph, decode_task, priority, 0u);
190
191    graph->edges.push_back(TaskGraph::Edge(decode_task, raster_task));
192  }
193
194  InsertNodeForTask(graph, raster_task, priority, dependencies);
195}
196
197// static
198void RasterWorkerPool::AcquireBitmapForBuffer(SkBitmap* bitmap,
199                                              uint8_t* buffer,
200                                              ResourceFormat buffer_format,
201                                              const gfx::Size& size,
202                                              int stride) {
203  switch (buffer_format) {
204    case RGBA_4444:
205      bitmap->allocN32Pixels(size.width(), size.height());
206      break;
207    case RGBA_8888:
208    case BGRA_8888: {
209      SkImageInfo info =
210          SkImageInfo::MakeN32Premul(size.width(), size.height());
211      if (!stride)
212        stride = info.minRowBytes();
213      bitmap->installPixels(info, buffer, stride);
214      break;
215    }
216    case ALPHA_8:
217    case LUMINANCE_8:
218    case RGB_565:
219    case ETC1:
220      NOTREACHED();
221      break;
222  }
223}
224
225// static
226void RasterWorkerPool::ReleaseBitmapForBuffer(SkBitmap* bitmap,
227                                              uint8_t* buffer,
228                                              ResourceFormat buffer_format) {
229  SkColorType buffer_color_type = ResourceFormatToSkColorType(buffer_format);
230  if (buffer_color_type != bitmap->colorType()) {
231    SkImageInfo dst_info = bitmap->info();
232    dst_info.fColorType = buffer_color_type;
233    // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
234    // bitmap data. There will be no need to call SkAlign4 once crbug.com/293728
235    // is fixed.
236    const size_t dst_row_bytes = SkAlign4(dst_info.minRowBytes());
237    DCHECK_EQ(0u, dst_row_bytes % 4);
238    bool success = bitmap->readPixels(dst_info, buffer, dst_row_bytes, 0, 0);
239    DCHECK_EQ(true, success);
240  }
241  bitmap->reset();
242}
243
244}  // namespace cc
245