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

Side by Side Diff: cc/tiles/image_controller.cc

Issue 2537683002: cc: Add image decode queue functionality to image manager. (Closed)
Patch Set: test fix Created 3 years, 11 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
« no previous file with comments | « cc/tiles/image_controller.h ('k') | cc/tiles/image_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/tiles/image_controller.h" 5 #include "cc/tiles/image_controller.h"
6 6
7 #include "base/bind.h"
8 #include "base/task_scheduler/post_task.h"
9 #include "base/task_scheduler/task_traits.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "base/trace_event/trace_event.h"
12 #include "cc/base/completion_event.h"
13 #include "cc/tiles/tile_task_manager.h"
14
7 namespace cc { 15 namespace cc {
8 16
9 ImageController::ImageController() = default; 17 ImageController::ImageDecodeRequestId
10 ImageController::~ImageController() = default; 18 ImageController::s_next_image_decode_queue_id_ = 1;
19
20 ImageController::ImageController(
21 base::SequencedTaskRunner* origin_task_runner,
22 scoped_refptr<base::SequencedTaskRunner> worker_task_runner)
23 : origin_task_runner_(origin_task_runner),
24 worker_task_runner_(std::move(worker_task_runner)),
25 weak_ptr_factory_(this) {}
26
27 ImageController::~ImageController() {
28 StopWorkerTasks();
29 }
30
31 void ImageController::StopWorkerTasks() {
32 // We can't have worker threads without a cache_ or a worker_task_runner_, so
33 // terminate early.
34 if (!cache_ || !worker_task_runner_)
35 return;
36
37 // Abort all tasks that are currently scheduled to run (we'll wait for them to
38 // finish next).
39 {
40 base::AutoLock hold(lock_);
41 abort_tasks_ = true;
42 }
43
44 // Post a task that will simply signal a completion event to ensure that we
45 // "flush" any scheduled tasks (they will abort).
46 CompletionEvent completion_event;
47 worker_task_runner_->PostTask(
48 FROM_HERE, base::Bind([](CompletionEvent* event) { event->Signal(); },
49 base::Unretained(&completion_event)));
50 completion_event.Wait();
51
52 // Reset the abort flag so that new tasks can be scheduled.
53 {
54 base::AutoLock hold(lock_);
55 abort_tasks_ = false;
56 }
57
58 // Now that we flushed everything, if there was a task running and it
59 // finished, it would have posted a completion callback back to the compositor
60 // thread. We don't want that, so invalidate the weak ptrs again. Note that
61 // nothing can start running between wait and this invalidate, since it would
62 // only run on the current (compositor) thread.
63 weak_ptr_factory_.InvalidateWeakPtrs();
64
65 // Now, begin cleanup.
66
67 // Unlock all of the locked images (note that this vector would only be
68 // populated if we actually need to unref the image.
69 for (auto image_pair : requested_locked_images_)
70 cache_->UnrefImage(image_pair.second);
71 requested_locked_images_.clear();
72
73 // Now, complete the tasks that already ran but haven't completed. These would
74 // be posted in the run loop, but since we invalidated the weak ptrs, we need
75 // to run everything manually.
76 for (auto& request_to_complete : requests_needing_completion_) {
77 ImageDecodeRequestId id = request_to_complete.first;
78 ImageDecodeRequest& request = request_to_complete.second;
79
80 // The task (if one exists) would have run already, so we just need to
81 // complete it.
82 if (request.task)
83 request.task->DidComplete();
84
85 // Issue the callback, and unref the image immediately. This is so that any
86 // code waiting on the callback can proceed, although we're breaking the
87 // promise of having this image decoded. This is unfortunate, but it seems
88 // like the least complexity to process an image decode controller becoming
89 // nullptr.
90 request.callback.Run(id);
91 if (request.need_unref)
92 cache_->UnrefImage(request.draw_image);
93 }
94 requests_needing_completion_.clear();
95
96 // Finally, complete all of the tasks that never started running. This is
97 // similar to the |requests_needing_completion_|, but happens at a different
98 // stage in the pipeline.
99 for (auto& request_pair : image_decode_queue_) {
100 ImageDecodeRequestId id = request_pair.first;
101 ImageDecodeRequest& request = request_pair.second;
102
103 if (request.task) {
104 // This task may have run via a different request, so only cancel it if
105 // it's "new". That is, the same task could have been referenced by
106 // several different image deque requests for the same image.
107 if (request.task->state().IsNew())
108 request.task->state().DidCancel();
109 request.task->DidComplete();
110 }
111 // Run the callback and unref the image.
112 request.callback.Run(id);
113 cache_->UnrefImage(request.draw_image);
114 }
115 image_decode_queue_.clear();
116 }
11 117
12 void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) { 118 void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
13 if (!cache) { 119 if (!cache) {
14 SetPredecodeImages(std::vector<DrawImage>(), 120 SetPredecodeImages(std::vector<DrawImage>(),
15 ImageDecodeCache::TracingInfo()); 121 ImageDecodeCache::TracingInfo());
122 StopWorkerTasks();
16 } 123 }
17 cache_ = cache; 124 cache_ = cache;
18 } 125 }
19 126
20 void ImageController::GetTasksForImagesAndRef( 127 void ImageController::GetTasksForImagesAndRef(
21 std::vector<DrawImage>* images, 128 std::vector<DrawImage>* images,
22 std::vector<scoped_refptr<TileTask>>* tasks, 129 std::vector<scoped_refptr<TileTask>>* tasks,
23 const ImageDecodeCache::TracingInfo& tracing_info) { 130 const ImageDecodeCache::TracingInfo& tracing_info) {
24 DCHECK(cache_); 131 DCHECK(cache_);
25 for (auto it = images->begin(); it != images->end();) { 132 for (auto it = images->begin(); it != images->end();) {
(...skipping 23 matching lines...) Expand all
49 std::vector<scoped_refptr<TileTask>> ImageController::SetPredecodeImages( 156 std::vector<scoped_refptr<TileTask>> ImageController::SetPredecodeImages(
50 std::vector<DrawImage> images, 157 std::vector<DrawImage> images,
51 const ImageDecodeCache::TracingInfo& tracing_info) { 158 const ImageDecodeCache::TracingInfo& tracing_info) {
52 std::vector<scoped_refptr<TileTask>> new_tasks; 159 std::vector<scoped_refptr<TileTask>> new_tasks;
53 GetTasksForImagesAndRef(&images, &new_tasks, tracing_info); 160 GetTasksForImagesAndRef(&images, &new_tasks, tracing_info);
54 UnrefImages(predecode_locked_images_); 161 UnrefImages(predecode_locked_images_);
55 predecode_locked_images_ = std::move(images); 162 predecode_locked_images_ = std::move(images);
56 return new_tasks; 163 return new_tasks;
57 } 164 }
58 165
166 ImageController::ImageDecodeRequestId ImageController::QueueImageDecode(
167 sk_sp<const SkImage> image,
168 const ImageDecodedCallback& callback) {
169 // We must not receive any image requests if we have no worker.
170 CHECK(worker_task_runner_);
171
172 // Generate the next id.
173 ImageDecodeRequestId id = s_next_image_decode_queue_id_++;
174
175 DCHECK(image);
176 auto image_bounds = image->bounds();
177 DrawImage draw_image(std::move(image), image_bounds, kNone_SkFilterQuality,
178 SkMatrix::I());
179
180 // Get the tasks for this decode.
181 scoped_refptr<TileTask> task;
182 bool need_unref =
183 cache_->GetOutOfRasterDecodeTaskForImageAndRef(draw_image, &task);
184 // If we don't need to unref this, we don't actually have a task.
185 DCHECK(need_unref || !task);
186
187 // Schedule the task and signal that there is more work.
188 base::AutoLock hold(lock_);
189 image_decode_queue_[id] =
190 ImageDecodeRequest(id, draw_image, callback, std::move(task), need_unref);
191
192 // If this is the only image decode request, schedule a task to run.
193 // Otherwise, the task will be scheduled in the previou task's completion.
194 if (image_decode_queue_.size() == 1) {
195 // Post a worker task.
196 worker_task_runner_->PostTask(
197 FROM_HERE,
198 base::Bind(&ImageController::ProcessNextImageDecodeOnWorkerThread,
199 base::Unretained(this)));
200 }
201
202 return id;
203 }
204
205 void ImageController::UnlockImageDecode(ImageDecodeRequestId id) {
206 // If the image exists, ie we actually need to unlock it, then do so.
207 auto it = requested_locked_images_.find(id);
208 if (it == requested_locked_images_.end())
209 return;
210
211 UnrefImages({it->second});
212 requested_locked_images_.erase(it);
213 }
214
215 void ImageController::ProcessNextImageDecodeOnWorkerThread() {
216 TRACE_EVENT0("cc", "ImageController::ProcessNextImageDecodeOnWorkerThread");
217 ImageDecodeRequest decode;
218 {
219 base::AutoLock hold(lock_);
220
221 // If we don't have any work, abort.
222 if (image_decode_queue_.empty() || abort_tasks_)
223 return;
224
225 // Take the next request from the queue.
226 auto decode_it = image_decode_queue_.begin();
227 DCHECK(decode_it != image_decode_queue_.end());
228 decode = std::move(decode_it->second);
229 image_decode_queue_.erase(decode_it);
230
231 // Notify that the task will need completion. Note that there are two cases
232 // where we process this. First, we might complete this task as a response
233 // to the posted task below. Second, we might complete it in
234 // StopWorkerTasks(). In either case, the task would have already run
235 // (either post task happens after running, or the thread was already joined
236 // which means the task ran). This means that we can put the decode into
237 // |requests_needing_completion_| here before actually running the task.
238 requests_needing_completion_[decode.id] = decode;
239 }
240
241 // Run the task if we need to run it. If the task state isn't new, then
242 // there is another task that is responsible for finishing it and cleaning
243 // up (and it already ran); we just need to post a completion callback.
244 // Note that the other tasks's completion will also run first, since the
245 // requests are ordered. So, when we process this task's completion, we
246 // won't actually do anything with the task and simply issue the callback.
247 if (decode.task && decode.task->state().IsNew()) {
248 decode.task->state().DidSchedule();
249 decode.task->state().DidStart();
250 decode.task->RunOnWorkerThread();
251 decode.task->state().DidFinish();
252 }
253 origin_task_runner_->PostTask(
254 FROM_HERE, base::Bind(&ImageController::ImageDecodeCompleted,
255 weak_ptr_factory_.GetWeakPtr(), decode.id));
256 }
257
258 void ImageController::ImageDecodeCompleted(ImageDecodeRequestId id) {
259 ImageDecodedCallback callback;
260 {
261 base::AutoLock hold(lock_);
262
263 auto request_it = requests_needing_completion_.find(id);
264 DCHECK(request_it != requests_needing_completion_.end());
265 id = request_it->first;
266 ImageDecodeRequest& request = request_it->second;
267
268 // If we need to unref this decode, then we have to put it into the locked
269 // images vector.
270 if (request.need_unref)
271 requested_locked_images_[id] = std::move(request.draw_image);
272
273 // If we have a task that isn't completed yet, we need to complete it.
274 if (request.task && !request.task->HasCompleted()) {
275 request.task->OnTaskCompleted();
276 request.task->DidComplete();
277 }
278 // Finally, save the callback so we can run it without the lock, and erase
279 // the request from |requests_needing_completion_|.
280 callback = std::move(request.callback);
281 requests_needing_completion_.erase(request_it);
282 }
283
284 // Post another task to run.
285 worker_task_runner_->PostTask(
286 FROM_HERE,
287 base::Bind(&ImageController::ProcessNextImageDecodeOnWorkerThread,
288 base::Unretained(this)));
289
290 // Finally run the requested callback.
291 callback.Run(id);
292 }
293
294 ImageController::ImageDecodeRequest::ImageDecodeRequest() = default;
295 ImageController::ImageDecodeRequest::ImageDecodeRequest(
296 ImageDecodeRequestId id,
297 const DrawImage& draw_image,
298 const ImageDecodedCallback& callback,
299 scoped_refptr<TileTask> task,
300 bool need_unref)
301 : id(id),
302 draw_image(draw_image),
303 callback(callback),
304 task(std::move(task)),
305 need_unref(need_unref) {}
306 ImageController::ImageDecodeRequest::ImageDecodeRequest(
307 ImageDecodeRequest&& other) = default;
308 ImageController::ImageDecodeRequest::ImageDecodeRequest(
309 const ImageDecodeRequest& other) = default;
310 ImageController::ImageDecodeRequest::~ImageDecodeRequest() = default;
311
312 ImageController::ImageDecodeRequest& ImageController::ImageDecodeRequest::
313 operator=(ImageDecodeRequest&& other) = default;
314 ImageController::ImageDecodeRequest& ImageController::ImageDecodeRequest::
315 operator=(const ImageDecodeRequest& other) = default;
316
59 } // namespace cc 317 } // namespace cc
OLDNEW
« no previous file with comments | « cc/tiles/image_controller.h ('k') | cc/tiles/image_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698