Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(452)

Side by Side Diff: cc/resources/pixel_buffer_raster_worker_pool.cc

Issue 16190002: cc: Add new RasterWorkerPool interface. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: pass unit tests Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/pixel_buffer_raster_worker_pool.h"
6
7 #include "cc/resources/resource.h"
8
9 namespace cc {
10
11 namespace {
12
13 class RootWorkerPoolTaskImpl : public internal::WorkerPoolTask {
14 public:
15 explicit RootWorkerPoolTaskImpl(
16 internal::WorkerPoolTask::TaskVector* dependencies)
17 : internal::WorkerPoolTask(dependencies) {
18 }
19
20 // Overridden from internal::WorkerPoolTask:
21 virtual void RunOnThread(unsigned thread_index) OVERRIDE {}
22 virtual void DispatchCompletionCallback() OVERRIDE {}
23
24 private:
25 virtual ~RootWorkerPoolTaskImpl() {}
26 };
27
28 class PixelBufferWorkerPoolTaskImpl : public internal::WorkerPoolTask {
29 public:
30 // First callback parameter is true when task was canceled. Second is
31 // true when upload is needed.
32 typedef base::Callback<void(bool, bool)> Reply;
33
34 PixelBufferWorkerPoolTaskImpl(internal::RasterWorkerPoolTask* task,
35 TaskVector* dependencies,
36 uint8_t* buffer,
37 const Reply& reply)
38 : internal::WorkerPoolTask(dependencies),
39 task_(task),
40 buffer_(buffer),
41 reply_(reply),
42 need_upload_(false) {
43 }
44
45 // Overridden from internal::WorkerPoolTask:
46 virtual void RunOnThread(unsigned thread_index) OVERRIDE {
47 need_upload_ = task_->RunOnThread(buffer_, thread_index);
48 }
49 virtual void DispatchCompletionCallback() OVERRIDE {
50 DCHECK(HasFinishedRunning() || !need_upload_);
51 reply_.Run(!HasFinishedRunning(), need_upload_);
52 }
53
54 private:
55 virtual ~PixelBufferWorkerPoolTaskImpl() {}
56
57 scoped_refptr<internal::RasterWorkerPoolTask> task_;
58 uint8_t* buffer_;
59 const Reply reply_;
60 bool need_upload_;
61 };
62
63 // If we raster too fast we become upload bound, and pending
64 // uploads consume memory. For maximum upload throughput, we would
65 // want to allow for upload_throughput * pipeline_time of pending
66 // uploads, after which we are just wasting memory. Since we don't
67 // know our upload throughput yet, this just caps our memory usage.
68 #if defined(OS_ANDROID)
69 // For reference, the Nexus10 can upload 1MB in about 2.5ms.
70 // Assuming a three frame deep pipeline this implies ~20MB.
71 const size_t kMaxPendingUploadBytes = 20 * 1024 * 1024;
72 // TODO(epenner): We should remove this upload limit (crbug.com/176197)
73 const size_t kMaxPendingUploads = 72;
74 #else
75 const size_t kMaxPendingUploadBytes = 100 * 1024 * 1024;
76 const size_t kMaxPendingUploads = 1000;
77 #endif
78
79 } // namespace
80
81 PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool(
82 ResourceProvider* resource_provider,
83 size_t num_threads) : RasterWorkerPool(resource_provider, num_threads),
84 bytes_pending_upload_(0),
85 has_performed_uploads_since_last_flush_(false),
86 did_dispatch_completion_callback_(false) {
87 // TODO(reveman): Remove WorkerPool client interface.
88 WorkerPool::SetClient(this);
89 }
90
91 PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() {
92 DCHECK_EQ(0u, pixel_buffer_tasks_.size());
93 DCHECK_EQ(0u, tasks_with_pending_upload_.size());
94 }
95
96 void PixelBufferRasterWorkerPool::Shutdown() {
97 RasterWorkerPool::Shutdown();
98 AbortPendingUploads();
99 for (TaskMap::iterator it = pixel_buffer_tasks_.begin();
100 it != pixel_buffer_tasks_.end(); ++it) {
101 internal::RasterWorkerPoolTask* task = it->first;
102 DCHECK(!it->second);
103
104 // Everything else has been canceled.
105 DidFinishRasterTask(task);
106 }
107 pixel_buffer_tasks_.clear();
108 }
109
110 void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
111 RasterWorkerPool::SetRasterTasks(queue);
112
113 // Build new pixel buffer task set.
114 TaskMap new_pixel_buffer_tasks;
115 for (RasterTask::Queue::TaskVector::iterator it = raster_tasks_.begin();
116 it != raster_tasks_.end(); ++it) {
117 internal::RasterWorkerPoolTask* task = *it;
118 DCHECK(new_pixel_buffer_tasks.find(task) == new_pixel_buffer_tasks.end());
119 DCHECK(!task->HasCompleted());
120
121 // Use existing pixel buffer task if available.
122 TaskMap::iterator pixel_buffer_it = pixel_buffer_tasks_.find(task);
123 if (pixel_buffer_it == pixel_buffer_tasks_.end()) {
124 new_pixel_buffer_tasks[task] = NULL;
125 continue;
126 }
127
128 new_pixel_buffer_tasks[task] = pixel_buffer_it->second;
129 pixel_buffer_tasks_.erase(task);
130 }
131
132 // Transfer activate pixel buffer tasks to |new_pixel_buffer_tasks|
vmpstr 2013/05/29 16:55:03 activate -> active
reveman 2013/05/29 19:39:12 Done.
133 // and cancel any remaining tasks.
134 for (TaskMap::iterator it = pixel_buffer_tasks_.begin();
135 it != pixel_buffer_tasks_.end(); ++it) {
136 internal::RasterWorkerPoolTask* task = it->first;
137
138 // Move task to |new_pixel_buffer_tasks|
139 if (it->second) {
140 new_pixel_buffer_tasks[task] = it->second;
141 continue;
142 }
143
144 // Everything else can be canceled.
145 DidFinishRasterTask(task);
146 }
147
148 pixel_buffer_tasks_.swap(new_pixel_buffer_tasks);
149
150 ScheduleMoreTasks();
151 }
152
153 void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
154 while (!tasks_with_pending_upload_.empty()) {
155 internal::RasterWorkerPoolTask* task = tasks_with_pending_upload_.front();
156
157 // Uploads complete in the order they are issued.
158 if (!resource_provider_->DidSetPixelsComplete(task->resource()->id()))
159 break;
160
161 // It's now safe to release the pixel buffer and the shared memory.
162 resource_provider_->ReleasePixelBuffer(task->resource()->id());
163
164 task->DidRun();
165 DidFinishRasterTask(task);
166 pixel_buffer_tasks_.erase(task);
167
168 bytes_pending_upload_ -= task->resource()->bytes();
169 tasks_with_pending_upload_.pop_front();
170 }
171
172 ScheduleMoreTasks();
173 }
174
175 bool PixelBufferRasterWorkerPool::ForceUploadToComplete(
176 ResourceProvider::ResourceId resource_id) {
177 for (TaskDeque::iterator it = tasks_with_pending_upload_.begin();
178 it != tasks_with_pending_upload_.end(); ++it) {
179 internal::RasterWorkerPoolTask* task = *it;
180 if (task->resource()->id() == resource_id) {
181 resource_provider_->ForceSetPixelsToComplete(resource_id);
182 return true;
183 }
184 }
185
186 return false;
187 }
188
189 void PixelBufferRasterWorkerPool::
190 DidFinishDispatchingWorkerPoolCompletionCallbacks() {
191 // If a flush is needed, do it now before starting to dispatch more tasks.
192 if (has_performed_uploads_since_last_flush_) {
193 resource_provider_->ShallowFlushIfSupported();
194 has_performed_uploads_since_last_flush_ = false;
195 }
196
197 ScheduleMoreTasks();
198 }
199
200 bool PixelBufferRasterWorkerPool::CanScheduleRasterTask(
201 internal::RasterWorkerPoolTask* task) {
202 if (tasks_with_pending_upload_.size() >= kMaxPendingUploads)
203 return false;
204 size_t new_bytes_pending = bytes_pending_upload_;
205 new_bytes_pending += task->resource()->bytes();
206 return new_bytes_pending <= kMaxPendingUploadBytes;
207 }
208
209 void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
210 internal::WorkerPoolTask::TaskVector tasks;
211
212 for (RasterTask::Queue::TaskVector::iterator it = raster_tasks_.begin();
213 it != raster_tasks_.end(); ++it) {
214 internal::RasterWorkerPoolTask* task = *it;
215
216 TaskMap::iterator pixel_buffer_it = pixel_buffer_tasks_.find(task);
217 if (pixel_buffer_it == pixel_buffer_tasks_.end())
218 continue;
219
220 scoped_refptr<internal::WorkerPoolTask> pixel_buffer_task(
221 pixel_buffer_it->second);
222 if (pixel_buffer_task) {
223 if (!pixel_buffer_task->HasCompleted())
224 tasks.push_back(pixel_buffer_task);
225 continue;
226 }
227
228 if (!CanScheduleRasterTask(task))
229 break;
230
231 // Request a pixel buffer. This will reserve shared memory.
232 resource_provider_->AcquirePixelBuffer(task->resource()->id());
233
234 // MapPixelBuffer() returns NULL if context was lost at the time
235 // AcquirePixelBuffer() was called. For simplicity we still post
236 // a raster task that is essentially a noop in these situations.
237 uint8* buffer = resource_provider_->MapPixelBuffer(task->resource()->id());
238
239 // TODO(reveman): Avoid having to make a copy of dependencies.
240 internal::WorkerPoolTask::TaskVector dependencies = task->dependencies();
241 pixel_buffer_task = make_scoped_refptr(
242 new PixelBufferWorkerPoolTaskImpl(
243 task,
244 &dependencies,
245 buffer,
246 base::Bind(&PixelBufferRasterWorkerPool::OnRasterTaskCompleted,
247 base::Unretained(this),
248 make_scoped_refptr(task))));
249
250 pixel_buffer_tasks_[task] = pixel_buffer_task;
251 tasks.push_back(pixel_buffer_task);
252 }
253
254 if (!tasks.empty()) {
255 scoped_refptr<RootWorkerPoolTaskImpl> root(
256 new RootWorkerPoolTaskImpl(&tasks));
257 WorkerPool::ScheduleTasks(root);
258 } else {
259 WorkerPool::ScheduleTasks(NULL);
260 }
261
262 if (did_dispatch_completion_callback_) {
263 did_dispatch_completion_callback_ = false;
264 client_->DidFinishDispatchingRasterWorkerPoolCompletionCallbacks();
265 }
266 }
267
268 void PixelBufferRasterWorkerPool::OnRasterTaskCompleted(
269 scoped_refptr<internal::RasterWorkerPoolTask> task,
270 bool was_canceled,
271 bool need_upload) {
272 DCHECK(pixel_buffer_tasks_.find(task) != pixel_buffer_tasks_.end());
273
274 // Balanced with MapPixelBuffer() call in ScheduleMoreTasks().
275 resource_provider_->UnmapPixelBuffer(task->resource()->id());
276
277 if (!need_upload) {
278 resource_provider_->ReleasePixelBuffer(task->resource()->id());
279 // No upload needed. Dispatch completion callback.
280 if (!was_canceled)
281 task->DidRun();
282
283 DidFinishRasterTask(task);
284 pixel_buffer_tasks_.erase(task);
285 return;
286 }
287
288 resource_provider_->BeginSetPixels(task->resource()->id());
289 has_performed_uploads_since_last_flush_ = true;
290
291 bytes_pending_upload_ += task->resource()->bytes();
292 tasks_with_pending_upload_.push_back(task);
293 }
294
295 void PixelBufferRasterWorkerPool::AbortPendingUploads() {
296 while (!tasks_with_pending_upload_.empty()) {
297 internal::RasterWorkerPoolTask* task = tasks_with_pending_upload_.front();
298
299 resource_provider_->AbortSetPixels(task->resource()->id());
300 resource_provider_->ReleasePixelBuffer(task->resource()->id());
301
302 // Need to run the reply callback even though task was aborted.
303 DidFinishRasterTask(task);
304 pixel_buffer_tasks_.erase(task);
305
306 bytes_pending_upload_ -= task->resource()->bytes();
307 tasks_with_pending_upload_.pop_front();
308 }
309 }
310
311 void PixelBufferRasterWorkerPool::DidFinishRasterTask(
312 internal::RasterWorkerPoolTask* task) {
313 task->DidComplete();
314 task->DispatchCompletionCallback();
315 did_dispatch_completion_callback_ = true;
316 }
317
318 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698