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 15 namespace cc { 16 namespace { 17 18 class 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 49 base::LazyInstance<RasterTaskGraphRunner>::Leaky g_task_graph_runner = 50 LAZY_INSTANCE_INITIALIZER; 51 52 const int kDefaultNumRasterThreads = 1; 53 54 int g_num_raster_threads = 0; 55 56 class 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. 93 unsigned RasterWorkerPool::kBenchmarkRasterTaskPriority = 0u; 94 // Task priorities that make sure raster finished tasks run before any 95 // remaining raster tasks. 96 unsigned RasterWorkerPool::kRasterFinishedTaskPriority = 1u; 97 unsigned RasterWorkerPool::kRasterTaskPriorityBase = 2u; 98 99 RasterWorkerPool::RasterWorkerPool() {} 100 101 RasterWorkerPool::~RasterWorkerPool() {} 102 103 // static 104 void 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 112 int 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 120 TaskGraphRunner* RasterWorkerPool::GetTaskGraphRunner() { 121 return g_task_graph_runner.Pointer(); 122 } 123 124 // static 125 scoped_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 133 void 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 152 void 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 164 void 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 198 void 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 226 void 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