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

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

Issue 2537683002: cc: Add image decode queue functionality to image manager. (Closed)
Patch Set: image-queue: update Created 4 years 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
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 "cc/tiles/tile_task_manager.h"
9
7 namespace cc { 10 namespace cc {
11 namespace {
12 class WorkerThread : public base::SimpleThread {
13 public:
14 WorkerThread(const std::string& name_prefix,
15 const Options& options,
16 ImageController* image_manager)
17 : base::SimpleThread(name_prefix, options),
18 image_manager_(image_manager) {}
8 19
9 ImageController::ImageController() = default; 20 void Run() override { image_manager_->ProcessImageDecodes(); }
10 ImageController::~ImageController() = default; 21
22 private:
23 ImageController* image_manager_ = nullptr;
24 };
25
26 const int kNumFramesToLock = 2;
27 } // namespace
28
29 ImageController::ImageDecodeRequestId
30 ImageController::s_next_image_decode_queue_id_ = 1;
31
32 ImageController::ImageController(base::SequencedTaskRunner* task_runner)
33 : task_runner_(task_runner),
34 work_available_cv_(&lock_),
35 weak_ptr_factory_(this) {
36 // Worker thread will be started when we get a controller.
37 }
38
39 ImageController::~ImageController() {
40 StopWorkerThread();
41 }
42
43 void ImageController::StartWorkerThread() {
44 DCHECK(!worker_thread_);
45
46 shutdown_ = false;
47 worker_thread_.reset(new WorkerThread(
48 "ImageDecodeWorker",
49 base::SimpleThread::Options(base::ThreadPriority::BACKGROUND), this));
50 worker_thread_->Start();
51 }
52
53 void ImageController::StopWorkerThread() {
54 if (shutdown_) {
55 DCHECK(!cache_);
56 DCHECK(!worker_thread_);
57 return;
58 }
59
60 // First thing, join the thread so we don't have any races in the rest of the
61 // function and so we don't need to acquire the lock.
62 shutdown_ = true;
63 work_available_cv_.Signal();
64 worker_thread_->Join();
65 worker_thread_.reset();
66
67 // Invalidate the weak ptrs, so any tasks to complete requests won't run (we
68 // will complete everything in this function).
69 weak_ptr_factory_.InvalidateWeakPtrs();
70
71 // Unlock all of the locked images (note that this vector would only be
72 // populated if we actually need to unref the image.
73 for (auto image_pair : requested_locked_images_)
74 cache_->UnrefImage(image_pair.first);
75 requested_locked_images_.clear();
76
77 // Now, complete the tasks that already ran but haven't completed. These would
78 // be posted in the run loop, but since we invalidated the weak ptrs, we need
79 // to run everything manually.
80 for (auto& request_to_complete : requests_needing_completion_) {
81 ImageDecodeRequestId id = request_to_complete.first;
82 ImageDecodeRequest& request = request_to_complete.second;
83
84 // The task (if one exists) would have run already, so we just need to
85 // complete it.
86 if (request.task)
87 request.task->DidComplete();
88
89 // Issue the callback, and unref the image immediately. This is so that any
90 // code waiting on the callback can proceed, although we're breaking the
91 // promise of having this image decoded. This is unfortunate, but it seems
92 // like the least complexity to process an image decode controller becoming
93 // nullptr.
94 request.callback.Run(id);
95 if (request.need_unref)
96 cache_->UnrefImage(request.draw_image);
97 }
98 requests_needing_completion_.clear();
99
100 // Finally, complete all of the tasks that never started running. This is
101 // similar to the |requests_needing_completion_|, but happens at a different
102 // stage in the pipeline.
103 for (auto& request_pair : image_decode_queue_) {
104 ImageDecodeRequestId id = request_pair.first;
105 ImageDecodeRequest& request = request_pair.second;
106
107 if (request.task) {
108 // This task may have run via a different request, so only cancel it if
109 // it's "new".
110 if (request.task->state().IsNew())
111 request.task->state().DidCancel();
112 request.task->DidComplete();
113 }
114 // Run the callback and unref the image.
115 request.callback.Run(id);
116 cache_->UnrefImage(request.draw_image);
117 }
118 image_decode_queue_.clear();
119 }
11 120
12 void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) { 121 void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
13 // We can only switch from null to non-null and back. 122 // We can only switch from null to non-null and back.
14 // CHECK to debug crbug.com/650234. 123 // CHECK to debug crbug.com/650234.
15 CHECK(cache || cache_); 124 CHECK(cache || cache_);
16 CHECK(!cache || !cache_); 125 CHECK(!cache || !cache_);
17 126
18 if (!cache) { 127 if (!cache) {
19 SetPredecodeImages(std::vector<DrawImage>(), 128 SetPredecodeImages(std::vector<DrawImage>(),
20 ImageDecodeCache::TracingInfo()); 129 ImageDecodeCache::TracingInfo());
130 StopWorkerThread();
21 } 131 }
22 cache_ = cache; 132 cache_ = cache;
133
134 if (cache_)
135 StartWorkerThread();
136
23 // Debugging information for crbug.com/650234. 137 // Debugging information for crbug.com/650234.
24 ++num_times_cache_was_set_; 138 ++num_times_cache_was_set_;
25 } 139 }
26 140
27 void ImageController::GetTasksForImagesAndRef( 141 void ImageController::GetTasksForImagesAndRef(
28 std::vector<DrawImage>* images, 142 std::vector<DrawImage>* images,
29 std::vector<scoped_refptr<TileTask>>* tasks, 143 std::vector<scoped_refptr<TileTask>>* tasks,
30 const ImageDecodeCache::TracingInfo& tracing_info) { 144 const ImageDecodeCache::TracingInfo& tracing_info) {
31 DCHECK(cache_); 145 DCHECK(cache_);
32 for (auto it = images->begin(); it != images->end();) { 146 for (auto it = images->begin(); it != images->end();) {
(...skipping 25 matching lines...) Expand all
58 std::vector<scoped_refptr<TileTask>> ImageController::SetPredecodeImages( 172 std::vector<scoped_refptr<TileTask>> ImageController::SetPredecodeImages(
59 std::vector<DrawImage> images, 173 std::vector<DrawImage> images,
60 const ImageDecodeCache::TracingInfo& tracing_info) { 174 const ImageDecodeCache::TracingInfo& tracing_info) {
61 std::vector<scoped_refptr<TileTask>> new_tasks; 175 std::vector<scoped_refptr<TileTask>> new_tasks;
62 GetTasksForImagesAndRef(&images, &new_tasks, tracing_info); 176 GetTasksForImagesAndRef(&images, &new_tasks, tracing_info);
63 UnrefImages(predecode_locked_images_); 177 UnrefImages(predecode_locked_images_);
64 predecode_locked_images_ = std::move(images); 178 predecode_locked_images_ = std::move(images);
65 return new_tasks; 179 return new_tasks;
66 } 180 }
67 181
182 ImageController::ImageDecodeRequestId ImageController::QueueImageDecode(
183 sk_sp<const SkImage> image,
184 const ImageDecodedCallback& callback) {
185 // Generate the next id.
186 ImageDecodeRequestId id = s_next_image_decode_queue_id_++;
187
188 DCHECK(image);
189 auto image_bounds = image->bounds();
190 DrawImage draw_image(std::move(image), image_bounds, kNone_SkFilterQuality,
191 SkMatrix::I());
192
193 // Get the tasks for this decode.
194 scoped_refptr<TileTask> task;
195 bool need_unref =
196 cache_->GetOutOfRasterDecodeTaskForImageAndRef(draw_image, &task);
197 // If we don't need to unref this, we don't actually have a task.
198 DCHECK(need_unref || !task);
199
200 // Schedule the task and signal that there is more work.
201 base::AutoLock hold(lock_);
202 image_decode_queue_[id] =
203 ImageDecodeRequest(id, draw_image, callback, std::move(task), need_unref);
204 work_available_cv_.Signal();
205 return id;
206 }
207
208 void ImageController::NotifyFrameFinished() {
209 // Reduce the locked frame count on all images and unlock them if the count
210 // reaches 0.
211 for (auto it = requested_locked_images_.begin();
212 it != requested_locked_images_.end();) {
213 if (--it->second == 0) {
214 UnrefImages({it->first});
215 it = requested_locked_images_.erase(it);
216 } else {
217 ++it;
218 }
219 }
220 }
221
222 void ImageController::ProcessImageDecodes() {
223 base::AutoLock hold(lock_);
224 for (;;) {
225 // Exit on shutdown, so the thread can be joined.
226 if (shutdown_)
227 break;
228
229 // If we don't have any work, wait until we get some.
230 if (image_decode_queue_.empty()) {
231 work_available_cv_.Wait();
232 continue;
233 }
234
235 // Take the next request from the queue.
236 auto decode_it = image_decode_queue_.begin();
237 DCHECK(decode_it != image_decode_queue_.end());
238 ImageDecodeRequest decode = std::move(decode_it->second);
239 image_decode_queue_.erase(decode_it);
240
241 // Notify that the task will need completion. Note that there are two cases
242 // where we process this. First, we might complete this task as a response
243 // to the posted task below. Second, we might complete it in
244 // StopWorkerThread(). In either case, the task would have already run
245 // (either post task happens after running, or the thread was already joined
246 // which means the task ran). This means that we can put the decode into
247 // |requests_needing_completion_| here before actually running the task.
248 requests_needing_completion_[decode.id] = decode;
249
250 {
251 base::AutoUnlock unlock(lock_);
252 // Run the task if we need to run it. If the task state isn't new, then
253 // there is another task that is responsible for finishing it and cleaning
254 // up (and it already ran); we just need to post a completion callback.
255 // Note that the other tasks's completion will also run first, since the
256 // requests are ordered. So, when we process this task's completion, we
257 // won't actually do anything with the task and simply issue the callback.
258 if (decode.task && decode.task->state().IsNew()) {
259 decode.task->state().DidSchedule();
260 decode.task->state().DidStart();
261 decode.task->RunOnWorkerThread();
262 decode.task->state().DidFinish();
263 }
264 task_runner_->PostTask(
265 FROM_HERE, base::Bind(&ImageController::ImageDecodeCompleted,
266 weak_ptr_factory_.GetWeakPtr(), decode.id));
267 }
268 }
269 }
270
271 void ImageController::ImageDecodeCompleted(ImageDecodeRequestId id) {
272 ImageDecodedCallback callback;
273 {
274 base::AutoLock hold(lock_);
275
276 auto request_it = requests_needing_completion_.find(id);
277 DCHECK(request_it != requests_needing_completion_.end());
278 id = request_it->first;
279 ImageDecodeRequest& request = request_it->second;
280
281 // If we need to urnef this decode, then we have to put it into the locked
282 // images vector.
283 if (request.need_unref) {
284 requested_locked_images_.push_back(
285 std::make_pair(std::move(request.draw_image), kNumFramesToLock));
286 }
287 // If we have a task that isn't completed yet, we need to complete it.
288 if (request.task && !request.task->HasCompleted()) {
289 request.task->OnTaskCompleted();
290 request.task->DidComplete();
291 }
292 // Finally, save the callback so we can run it without the lock, and erase
293 // the request from |requests_needing_completion_|.
294 callback = std::move(request.callback);
295 requests_needing_completion_.erase(request_it);
296 }
297 callback.Run(id);
298 }
299
300 ImageController::ImageDecodeRequest::ImageDecodeRequest() = default;
301 ImageController::ImageDecodeRequest::ImageDecodeRequest(
302 ImageDecodeRequestId id,
303 const DrawImage& draw_image,
304 const ImageDecodedCallback& callback,
305 scoped_refptr<TileTask> task,
306 bool need_unref)
307 : id(id),
308 draw_image(draw_image),
309 callback(callback),
310 task(std::move(task)),
311 need_unref(need_unref) {}
312 ImageController::ImageDecodeRequest::ImageDecodeRequest(
313 ImageDecodeRequest&& other) = default;
314 ImageController::ImageDecodeRequest::ImageDecodeRequest(
315 const ImageDecodeRequest& other) = default;
316 ImageController::ImageDecodeRequest::~ImageDecodeRequest() = default;
317
318 ImageController::ImageDecodeRequest& ImageController::ImageDecodeRequest::
319 operator=(ImageDecodeRequest&& other) = default;
320 ImageController::ImageDecodeRequest& ImageController::ImageDecodeRequest::
321 operator=(const ImageDecodeRequest& other) = default;
322
68 } // namespace cc 323 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698