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.
5 #include "cc/resources/raster_worker_pool.h"
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 #include "cc/resources/raster_source.h"
15 #include "skia/ext/refptr.h"
16 #include "third_party/skia/include/core/SkCanvas.h"
17 #include "third_party/skia/include/core/SkSurface.h"
22 class RasterTaskGraphRunner
: public TaskGraphRunner
,
23 public base::DelegateSimpleThread::Delegate
{
25 RasterTaskGraphRunner() {
26 size_t num_threads
= RasterWorkerPool::GetNumRasterThreads();
27 while (workers_
.size() < num_threads
) {
28 scoped_ptr
<base::DelegateSimpleThread
> worker
=
29 make_scoped_ptr(new base::DelegateSimpleThread(
31 base::StringPrintf("CompositorRasterWorker%u",
32 static_cast<unsigned>(workers_
.size() + 1))
35 #if defined(OS_ANDROID) || defined(OS_LINUX)
36 worker
->SetThreadPriority(base::kThreadPriority_Background
);
38 workers_
.push_back(worker
.Pass());
42 ~RasterTaskGraphRunner() override
{ NOTREACHED(); }
45 // Overridden from base::DelegateSimpleThread::Delegate:
46 void Run() override
{ TaskGraphRunner::Run(); }
48 ScopedPtrDeque
<base::DelegateSimpleThread
> workers_
;
51 base::LazyInstance
<RasterTaskGraphRunner
>::Leaky g_task_graph_runner
=
52 LAZY_INSTANCE_INITIALIZER
;
54 const int kDefaultNumRasterThreads
= 1;
56 int g_num_raster_threads
= 0;
58 class RasterFinishedTaskImpl
: public RasterizerTask
{
60 explicit RasterFinishedTaskImpl(
61 base::SequencedTaskRunner
* task_runner
,
62 const base::Closure
& on_raster_finished_callback
)
63 : task_runner_(task_runner
),
64 on_raster_finished_callback_(on_raster_finished_callback
) {}
66 // Overridden from Task:
67 void RunOnWorkerThread() override
{
68 TRACE_EVENT0("cc", "RasterFinishedTaskImpl::RunOnWorkerThread");
72 // Overridden from RasterizerTask:
73 void ScheduleOnOriginThread(RasterizerTaskClient
* client
) override
{}
74 void CompleteOnOriginThread(RasterizerTaskClient
* client
) override
{}
75 void RunReplyOnOriginThread() override
{}
78 ~RasterFinishedTaskImpl() override
{}
80 void RasterFinished() {
81 task_runner_
->PostTask(FROM_HERE
, on_raster_finished_callback_
);
85 scoped_refptr
<base::SequencedTaskRunner
> task_runner_
;
86 const base::Closure on_raster_finished_callback_
;
88 DISALLOW_COPY_AND_ASSIGN(RasterFinishedTaskImpl
);
93 // This allows a micro benchmark system to run tasks with highest priority,
94 // since it should finish as quickly as possible.
95 unsigned RasterWorkerPool::kBenchmarkRasterTaskPriority
= 0u;
96 // Task priorities that make sure raster finished tasks run before any
97 // remaining raster tasks.
98 unsigned RasterWorkerPool::kRasterFinishedTaskPriority
= 1u;
99 unsigned RasterWorkerPool::kRasterTaskPriorityBase
= 2u;
101 RasterWorkerPool::RasterWorkerPool() {}
103 RasterWorkerPool::~RasterWorkerPool() {}
106 void RasterWorkerPool::SetNumRasterThreads(int num_threads
) {
107 DCHECK_LT(0, num_threads
);
108 DCHECK_EQ(0, g_num_raster_threads
);
110 g_num_raster_threads
= num_threads
;
114 int RasterWorkerPool::GetNumRasterThreads() {
115 if (!g_num_raster_threads
)
116 g_num_raster_threads
= kDefaultNumRasterThreads
;
118 return g_num_raster_threads
;
122 TaskGraphRunner
* RasterWorkerPool::GetTaskGraphRunner() {
123 return g_task_graph_runner
.Pointer();
127 scoped_refptr
<RasterizerTask
> RasterWorkerPool::CreateRasterFinishedTask(
128 base::SequencedTaskRunner
* task_runner
,
129 const base::Closure
& on_raster_finished_callback
) {
130 return make_scoped_refptr(
131 new RasterFinishedTaskImpl(task_runner
, on_raster_finished_callback
));
135 void RasterWorkerPool::ScheduleTasksOnOriginThread(RasterizerTaskClient
* client
,
137 TRACE_EVENT0("cc", "Rasterizer::ScheduleTasksOnOriginThread");
139 for (TaskGraph::Node::Vector::iterator it
= graph
->nodes
.begin();
140 it
!= graph
->nodes
.end();
142 TaskGraph::Node
& node
= *it
;
143 RasterizerTask
* task
= static_cast<RasterizerTask
*>(node
.task
);
145 if (!task
->HasBeenScheduled()) {
146 task
->WillSchedule();
147 task
->ScheduleOnOriginThread(client
);
154 void RasterWorkerPool::InsertNodeForTask(TaskGraph
* graph
,
155 RasterizerTask
* task
,
157 size_t dependencies
) {
158 DCHECK(std::find_if(graph
->nodes
.begin(),
160 TaskGraph::Node::TaskComparator(task
)) ==
162 graph
->nodes
.push_back(TaskGraph::Node(task
, priority
, dependencies
));
166 void RasterWorkerPool::InsertNodesForRasterTask(
168 RasterTask
* raster_task
,
169 const ImageDecodeTask::Vector
& decode_tasks
,
171 size_t dependencies
= 0u;
173 // Insert image decode tasks.
174 for (ImageDecodeTask::Vector::const_iterator it
= decode_tasks
.begin();
175 it
!= decode_tasks
.end();
177 ImageDecodeTask
* decode_task
= it
->get();
179 // Skip if already decoded.
180 if (decode_task
->HasCompleted())
185 // Add decode task if it doesn't already exists in graph.
186 TaskGraph::Node::Vector::iterator decode_it
=
187 std::find_if(graph
->nodes
.begin(),
189 TaskGraph::Node::TaskComparator(decode_task
));
190 if (decode_it
== graph
->nodes
.end())
191 InsertNodeForTask(graph
, decode_task
, priority
, 0u);
193 graph
->edges
.push_back(TaskGraph::Edge(decode_task
, raster_task
));
196 InsertNodeForTask(graph
, raster_task
, priority
, dependencies
);
199 static bool IsSupportedPlaybackToMemoryFormat(ResourceFormat format
) {
216 void RasterWorkerPool::PlaybackToMemory(void* memory
,
217 ResourceFormat format
,
218 const gfx::Size
& size
,
220 const RasterSource
* raster_source
,
221 const gfx::Rect
& rect
,
223 DCHECK(IsSupportedPlaybackToMemoryFormat(format
)) << format
;
225 // Uses kPremul_SkAlphaType since the result is not known to be opaque.
227 SkImageInfo::MakeN32(size
.width(), size
.height(), kPremul_SkAlphaType
);
228 SkColorType buffer_color_type
= ResourceFormatToSkColorType(format
);
229 bool needs_copy
= buffer_color_type
!= info
.colorType();
231 // Use unknown pixel geometry to disable LCD text.
232 SkSurfaceProps
surface_props(0, kUnknown_SkPixelGeometry
);
233 if (raster_source
->CanUseLCDText()) {
234 // LegacyFontHost will get LCD text and skia figures out what type to use.
235 surface_props
= SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType
);
239 stride
= info
.minRowBytes();
242 skia::RefPtr
<SkSurface
> surface
= skia::AdoptRef(
243 SkSurface::NewRasterDirect(info
, memory
, stride
, &surface_props
));
244 skia::RefPtr
<SkCanvas
> canvas
= skia::SharePtr(surface
->getCanvas());
245 raster_source
->PlaybackToCanvas(canvas
.get(), rect
, scale
);
249 skia::RefPtr
<SkSurface
> surface
=
250 skia::AdoptRef(SkSurface::NewRaster(info
, &surface_props
));
251 skia::RefPtr
<SkCanvas
> canvas
= skia::SharePtr(surface
->getCanvas());
252 raster_source
->PlaybackToCanvas(canvas
.get(), rect
, scale
);
254 SkImageInfo dst_info
= info
;
255 dst_info
.fColorType
= buffer_color_type
;
256 // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
257 // bitmap data. There will be no need to call SkAlign4 once crbug.com/293728
259 const size_t dst_row_bytes
= SkAlign4(dst_info
.minRowBytes());
260 DCHECK_EQ(0u, dst_row_bytes
% 4);
261 bool success
= canvas
->readPixels(dst_info
, memory
, dst_row_bytes
, 0, 0);
262 DCHECK_EQ(true, success
);