1 // Copyright 2014 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/gpu_raster_worker_pool.h"
6
7 #include <algorithm>
8
9 #include "base/debug/trace_event.h"
10 #include "cc/output/context_provider.h"
11 #include "cc/resources/raster_buffer.h"
12 #include "cc/resources/resource.h"
13 #include "cc/resources/resource_provider.h"
14 #include "cc/resources/scoped_gpu_raster.h"
15 #include "gpu/command_buffer/client/gles2_interface.h"
16 #include "third_party/skia/include/core/SkMultiPictureDraw.h"
17 #include "third_party/skia/include/core/SkPictureRecorder.h"
18 #include "third_party/skia/include/core/SkSurface.h"
19 #include "third_party/skia/include/gpu/GrContext.h"
20 #include "third_party/skia/include/utils/SkNullCanvas.h"
21
22 namespace cc {
23 namespace {
24
25 class RasterBufferImpl : public RasterBuffer {
26 public:
RasterBufferImpl(ResourceProvider * resource_provider,const Resource * resource,SkMultiPictureDraw * multi_picture_draw)27 RasterBufferImpl(ResourceProvider* resource_provider,
28 const Resource* resource,
29 SkMultiPictureDraw* multi_picture_draw)
30 : resource_provider_(resource_provider),
31 resource_(resource),
32 surface_(resource_provider->LockForWriteToSkSurface(resource->id())),
33 multi_picture_draw_(multi_picture_draw) {}
~RasterBufferImpl()34 virtual ~RasterBufferImpl() {
35 resource_provider_->UnlockForWriteToSkSurface(resource_->id());
36 }
37
38 // Overridden from RasterBuffer:
AcquireSkCanvas()39 virtual skia::RefPtr<SkCanvas> AcquireSkCanvas() OVERRIDE {
40 if (!surface_)
41 return skia::AdoptRef(SkCreateNullCanvas());
42
43 skia::RefPtr<SkCanvas> canvas = skia::SharePtr(recorder_.beginRecording(
44 resource_->size().width(), resource_->size().height()));
45
46 // Balanced with restore() call in ReleaseSkCanvas. save()/restore() calls
47 // are needed to ensure that canvas returns to its previous state after use.
48 canvas->save();
49 return canvas;
50 }
ReleaseSkCanvas(const skia::RefPtr<SkCanvas> & canvas)51 virtual void ReleaseSkCanvas(const skia::RefPtr<SkCanvas>& canvas) OVERRIDE {
52 if (!surface_)
53 return;
54
55 // Balanced with save() call in AcquireSkCanvas.
56 canvas->restore();
57
58 // Add the canvas and recorded picture to |multi_picture_draw_|.
59 skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder_.endRecording());
60 multi_picture_draw_->add(surface_->getCanvas(), picture.get());
61 }
62
63 private:
64 ResourceProvider* resource_provider_;
65 const Resource* resource_;
66 SkSurface* surface_;
67 SkMultiPictureDraw* multi_picture_draw_;
68 SkPictureRecorder recorder_;
69
70 DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
71 };
72
73 } // namespace
74
75 // static
Create(base::SequencedTaskRunner * task_runner,ContextProvider * context_provider,ResourceProvider * resource_provider)76 scoped_ptr<RasterWorkerPool> GpuRasterWorkerPool::Create(
77 base::SequencedTaskRunner* task_runner,
78 ContextProvider* context_provider,
79 ResourceProvider* resource_provider) {
80 return make_scoped_ptr<RasterWorkerPool>(new GpuRasterWorkerPool(
81 task_runner, context_provider, resource_provider));
82 }
83
GpuRasterWorkerPool(base::SequencedTaskRunner * task_runner,ContextProvider * context_provider,ResourceProvider * resource_provider)84 GpuRasterWorkerPool::GpuRasterWorkerPool(base::SequencedTaskRunner* task_runner,
85 ContextProvider* context_provider,
86 ResourceProvider* resource_provider)
87 : task_runner_(task_runner),
88 task_graph_runner_(new TaskGraphRunner),
89 namespace_token_(task_graph_runner_->GetNamespaceToken()),
90 context_provider_(context_provider),
91 resource_provider_(resource_provider),
92 run_tasks_on_origin_thread_pending_(false),
93 raster_finished_weak_ptr_factory_(this),
94 weak_ptr_factory_(this) {
95 DCHECK(context_provider_);
96 }
97
~GpuRasterWorkerPool()98 GpuRasterWorkerPool::~GpuRasterWorkerPool() {
99 DCHECK_EQ(0u, completed_tasks_.size());
100 }
101
AsRasterizer()102 Rasterizer* GpuRasterWorkerPool::AsRasterizer() {
103 return this;
104 }
105
SetClient(RasterizerClient * client)106 void GpuRasterWorkerPool::SetClient(RasterizerClient* client) {
107 client_ = client;
108 }
109
Shutdown()110 void GpuRasterWorkerPool::Shutdown() {
111 TRACE_EVENT0("cc", "GpuRasterWorkerPool::Shutdown");
112
113 TaskGraph empty;
114 task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
115 task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
116 }
117
ScheduleTasks(RasterTaskQueue * queue)118 void GpuRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
119 TRACE_EVENT0("cc", "GpuRasterWorkerPool::ScheduleTasks");
120
121 // Mark all task sets as pending.
122 raster_pending_.set();
123
124 unsigned priority = kRasterTaskPriorityBase;
125
126 graph_.Reset();
127
128 // Cancel existing OnRasterFinished callbacks.
129 raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
130
131 scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets];
132
133 size_t task_count[kNumberOfTaskSets] = {0};
134
135 for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
136 new_raster_finished_tasks[task_set] = CreateRasterFinishedTask(
137 task_runner_.get(),
138 base::Bind(&GpuRasterWorkerPool::OnRasterFinished,
139 raster_finished_weak_ptr_factory_.GetWeakPtr(),
140 task_set));
141 }
142
143 for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
144 it != queue->items.end();
145 ++it) {
146 const RasterTaskQueue::Item& item = *it;
147 RasterTask* task = item.task;
148 DCHECK(!task->HasCompleted());
149
150 for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
151 if (!item.task_sets[task_set])
152 continue;
153
154 ++task_count[task_set];
155
156 graph_.edges.push_back(
157 TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get()));
158 }
159
160 InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
161 }
162
163 for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
164 InsertNodeForTask(&graph_,
165 new_raster_finished_tasks[task_set].get(),
166 kRasterFinishedTaskPriority,
167 task_count[task_set]);
168 }
169
170 ScheduleTasksOnOriginThread(this, &graph_);
171 task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
172
173 ScheduleRunTasksOnOriginThread();
174
175 std::copy(new_raster_finished_tasks,
176 new_raster_finished_tasks + kNumberOfTaskSets,
177 raster_finished_tasks_);
178 }
179
CheckForCompletedTasks()180 void GpuRasterWorkerPool::CheckForCompletedTasks() {
181 TRACE_EVENT0("cc", "GpuRasterWorkerPool::CheckForCompletedTasks");
182
183 task_graph_runner_->CollectCompletedTasks(namespace_token_,
184 &completed_tasks_);
185 for (Task::Vector::const_iterator it = completed_tasks_.begin();
186 it != completed_tasks_.end();
187 ++it) {
188 RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
189
190 task->WillComplete();
191 task->CompleteOnOriginThread(this);
192 task->DidComplete();
193
194 task->RunReplyOnOriginThread();
195 }
196 completed_tasks_.clear();
197 }
198
AcquireBufferForRaster(const Resource * resource)199 scoped_ptr<RasterBuffer> GpuRasterWorkerPool::AcquireBufferForRaster(
200 const Resource* resource) {
201 // RasterBuffer implementation depends on a SkSurface having been acquired for
202 // the resource.
203 resource_provider_->AcquireSkSurface(resource->id());
204
205 return make_scoped_ptr<RasterBuffer>(
206 new RasterBufferImpl(resource_provider_, resource, &multi_picture_draw_));
207 }
208
ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer)209 void GpuRasterWorkerPool::ReleaseBufferForRaster(
210 scoped_ptr<RasterBuffer> buffer) {
211 // Nothing to do here. RasterBufferImpl destructor cleans up after itself.
212 }
213
OnRasterFinished(TaskSet task_set)214 void GpuRasterWorkerPool::OnRasterFinished(TaskSet task_set) {
215 TRACE_EVENT1(
216 "cc", "GpuRasterWorkerPool::OnRasterFinished", "task_set", task_set);
217
218 DCHECK(raster_pending_[task_set]);
219 raster_pending_[task_set] = false;
220 client_->DidFinishRunningTasks(task_set);
221 }
222
ScheduleRunTasksOnOriginThread()223 void GpuRasterWorkerPool::ScheduleRunTasksOnOriginThread() {
224 if (run_tasks_on_origin_thread_pending_)
225 return;
226
227 task_runner_->PostTask(
228 FROM_HERE,
229 base::Bind(&GpuRasterWorkerPool::RunTasksOnOriginThread,
230 weak_ptr_factory_.GetWeakPtr()));
231 run_tasks_on_origin_thread_pending_ = true;
232 }
233
RunTasksOnOriginThread()234 void GpuRasterWorkerPool::RunTasksOnOriginThread() {
235 TRACE_EVENT0("cc", "GpuRasterWorkerPool::RunTasksOnOriginThread");
236
237 DCHECK(run_tasks_on_origin_thread_pending_);
238 run_tasks_on_origin_thread_pending_ = false;
239
240 ScopedGpuRaster gpu_raster(context_provider_);
241 task_graph_runner_->RunUntilIdle();
242
243 // Draw each all of the pictures that were collected. This will also clear
244 // the pictures and canvases added to |multi_picture_draw_|
245 multi_picture_draw_.draw();
246 }
247
248 } // namespace cc
249