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

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

Issue 2537683002: cc: Add image decode queue functionality to image manager. (Closed)
Patch Set: image-decode: update 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
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 "base/bind.h"
6 #include "base/optional.h"
7 #include "base/run_loop.h"
8 #include "base/test/test_simple_task_runner.h"
9 #include "base/threading/sequenced_task_runner_handle.h"
5 #include "cc/tiles/image_controller.h" 10 #include "cc/tiles/image_controller.h"
6 #include "cc/tiles/image_decode_cache.h" 11 #include "cc/tiles/image_decode_cache.h"
7 #include "testing/gtest/include/gtest/gtest.h" 12 #include "testing/gtest/include/gtest/gtest.h"
8 13
9 namespace cc { 14 namespace cc {
15 namespace {
10 16
17 class TestWorkerThread : public base::SimpleThread {
18 public:
19 TestWorkerThread()
20 : base::SimpleThread("test_worker_thread"), condition_(&lock_) {}
21
22 void Run() override {
23 for (;;) {
24 base::AutoLock hold(lock_);
25 if (shutdown_)
26 break;
27
28 if (queue_.empty()) {
29 condition_.Wait();
30 continue;
31 }
32
33 queue_.front().Run();
34 queue_.erase(queue_.begin());
35 }
36 }
37
38 void Shutdown() {
39 base::AutoLock hold(lock_);
40 shutdown_ = true;
41 condition_.Signal();
42 }
43
44 void PostTask(const base::Closure& task) {
45 base::AutoLock hold(lock_);
46 queue_.push_back(task);
47 condition_.Signal();
48 }
49
50 private:
51 base::Lock lock_;
52 base::ConditionVariable condition_;
53 std::vector<base::Closure> queue_;
54 bool shutdown_ = false;
55 };
56
57 class WorkerTaskRunner : public base::SequencedTaskRunner {
58 public:
59 WorkerTaskRunner() { thread_.Start(); }
60
61 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
62 const base::Closure& task,
63 base::TimeDelta delay) override {
64 return PostDelayedTask(from_here, task, delay);
65 }
66
67 bool PostDelayedTask(const tracked_objects::Location& from_here,
68 const base::Closure& task,
69 base::TimeDelta delay) override {
70 thread_.PostTask(task);
71 return true;
72 }
73
74 bool RunsTasksOnCurrentThread() const override { return false; }
75
76 protected:
77 ~WorkerTaskRunner() override {
78 thread_.Shutdown();
79 thread_.Join();
80 }
81
82 TestWorkerThread thread_;
83 };
84
85 // Image decode cache with introspection!
11 class TestableCache : public ImageDecodeCache { 86 class TestableCache : public ImageDecodeCache {
12 public: 87 public:
88 ~TestableCache() override { EXPECT_EQ(number_of_refs_, 0); }
89
13 bool GetTaskForImageAndRef(const DrawImage& image, 90 bool GetTaskForImageAndRef(const DrawImage& image,
14 const TracingInfo& tracing_info, 91 const TracingInfo& tracing_info,
15 scoped_refptr<TileTask>* task) override { 92 scoped_refptr<TileTask>* task) override {
16 *task = nullptr; 93 *task = task_to_use_;
17 ++number_of_refs_; 94 ++number_of_refs_;
18 return true; 95 return true;
19 } 96 }
97 bool GetOutOfRasterDecodeTaskForImageAndRef(
98 const DrawImage& image,
99 scoped_refptr<TileTask>* task) override {
100 *task = task_to_use_;
101 ++number_of_refs_;
102 return true;
103 }
20 104
21 void UnrefImage(const DrawImage& image) override { 105 void UnrefImage(const DrawImage& image) override {
22 ASSERT_GT(number_of_refs_, 0); 106 ASSERT_GT(number_of_refs_, 0);
23 --number_of_refs_; 107 --number_of_refs_;
24 } 108 }
25 DecodedDrawImage GetDecodedImageForDraw(const DrawImage& image) override { 109 DecodedDrawImage GetDecodedImageForDraw(const DrawImage& image) override {
26 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); 110 return DecodedDrawImage(nullptr, kNone_SkFilterQuality);
27 } 111 }
28 void DrawWithImageFinished(const DrawImage& image, 112 void DrawWithImageFinished(const DrawImage& image,
29 const DecodedDrawImage& decoded_image) override {} 113 const DecodedDrawImage& decoded_image) override {}
30 void ReduceCacheUsage() override {} 114 void ReduceCacheUsage() override {}
31 void SetShouldAggressivelyFreeResources( 115 void SetShouldAggressivelyFreeResources(
32 bool aggressively_free_resources) override {} 116 bool aggressively_free_resources) override {}
33 117
34 int number_of_refs() const { return number_of_refs_; } 118 int number_of_refs() const { return number_of_refs_; }
119 void SetTaskToUse(scoped_refptr<TileTask> task) { task_to_use_ = task; }
35 120
36 private: 121 private:
37 int number_of_refs_ = 0; 122 int number_of_refs_ = 0;
38 }; 123 scoped_refptr<TileTask> task_to_use_;
39 124 };
40 TEST(ImageControllerTest, NullCacheUnrefsImages) { 125
41 TestableCache cache; 126 // A simple class that can receive decode callbacks.
42 ImageController controller; 127 class DecodeClient {
43 controller.SetImageDecodeCache(&cache); 128 public:
44 129 DecodeClient() {}
130 void Callback(const base::Closure& quit_closure,
131 ImageController::ImageDecodeRequestId id) {
132 id_ = id;
133 quit_closure.Run();
134 }
135
136 ImageController::ImageDecodeRequestId id() { return id_; }
137
138 private:
139 ImageController::ImageDecodeRequestId id_ = 0;
140 };
141
142 // A dummy task that does nothing.
143 class SimpleTask : public TileTask {
144 public:
145 SimpleTask() : TileTask(true /* supports_concurrent_execution */) {
146 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
147 }
148
149 void RunOnWorkerThread() override {
150 EXPECT_FALSE(HasCompleted());
151 EXPECT_FALSE(thread_checker_.CalledOnValidThread());
152 has_run_ = true;
153 }
154 void OnTaskCompleted() override {
155 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
156 }
157
158 bool has_run() { return has_run_; }
159
160 private:
161 ~SimpleTask() override = default;
162
163 base::ThreadChecker thread_checker_;
164 bool has_run_ = false;
165
166 DISALLOW_COPY_AND_ASSIGN(SimpleTask);
167 };
168
169 // A task that blocks until instructed otherwise.
170 class BlockingTask : public TileTask {
171 public:
172 BlockingTask()
173 : TileTask(true /* supports_concurrent_execution */), run_cv_(&lock_) {
174 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
175 }
176
177 void RunOnWorkerThread() override {
178 EXPECT_FALSE(HasCompleted());
179 EXPECT_FALSE(thread_checker_.CalledOnValidThread());
180 base::AutoLock hold(lock_);
181 if (!can_run_)
182 run_cv_.Wait();
183 has_run_ = true;
184 }
185
186 void OnTaskCompleted() override {
187 EXPECT_TRUE(thread_checker_.CalledOnValidThread());
188 }
189
190 void AllowToRun() {
191 base::AutoLock hold(lock_);
192 can_run_ = true;
193 run_cv_.Signal();
194 }
195
196 bool has_run() { return has_run_; }
197
198 private:
199 ~BlockingTask() override = default;
200
201 base::ThreadChecker thread_checker_;
202 bool has_run_ = false;
203 base::Lock lock_;
204 base::ConditionVariable run_cv_;
205 bool can_run_ = false;
206
207 DISALLOW_COPY_AND_ASSIGN(BlockingTask);
208 };
209
210 // For tests that exercise image controller's thread, this is the timeout value
211 // to
212 // allow the worker thread to do its work.
213 int kDefaultTimeoutSeconds = 10;
214
215 class ImageControllerTest : public testing::Test {
216 public:
217 ImageControllerTest() : task_runner_(base::SequencedTaskRunnerHandle::Get()) {
218 bitmap_.allocN32Pixels(1, 1);
219 image_ = SkImage::MakeFromBitmap(bitmap_);
220 }
221 ~ImageControllerTest() override = default;
222
223 void SetUp() override {
224 worker_task_runner_ = make_scoped_refptr(new WorkerTaskRunner);
225 controller_.reset(
226 new ImageController(task_runner_.get(), worker_task_runner_));
227 cache_ = TestableCache();
228 controller_->SetImageDecodeCache(&cache_);
229 }
230
231 void TearDown() override {
232 controller_.reset();
233 worker_task_runner_ = nullptr;
234 }
235
236 base::SequencedTaskRunner* task_runner() { return task_runner_.get(); }
237 ImageController* controller() { return controller_.get(); }
238 TestableCache* cache() { return &cache_; }
239 sk_sp<const SkImage> image() const { return image_; }
240
241 // Timeout callback, which errors and exits the runloop.
242 static void Timeout(base::RunLoop* run_loop) {
243 ADD_FAILURE() << "Timeout.";
244 run_loop->Quit();
245 }
246
247 // Convenience method to run the run loop with a timeout.
248 void RunOrTimeout(base::RunLoop* run_loop) {
249 task_runner_->PostDelayedTask(
250 FROM_HERE,
251 base::Bind(&ImageControllerTest::Timeout, base::Unretained(run_loop)),
252 base::TimeDelta::FromSeconds(kDefaultTimeoutSeconds));
253 run_loop->Run();
254 }
255
256 private:
257 scoped_refptr<base::SequencedTaskRunner> task_runner_;
258 scoped_refptr<WorkerTaskRunner> worker_task_runner_;
259 TestableCache cache_;
260 std::unique_ptr<ImageController> controller_;
261 SkBitmap bitmap_;
262 sk_sp<const SkImage> image_;
263 };
264
265 TEST_F(ImageControllerTest, NullControllerUnrefsImages) {
45 std::vector<DrawImage> images(10); 266 std::vector<DrawImage> images(10);
46 ImageDecodeCache::TracingInfo tracing_info; 267 ImageDecodeCache::TracingInfo tracing_info;
47 268
48 ASSERT_EQ(10u, images.size()); 269 ASSERT_EQ(10u, images.size());
49 auto tasks = controller.SetPredecodeImages(std::move(images), tracing_info); 270 auto tasks =
271 controller()->SetPredecodeImages(std::move(images), tracing_info);
50 EXPECT_EQ(0u, tasks.size()); 272 EXPECT_EQ(0u, tasks.size());
51 EXPECT_EQ(10, cache.number_of_refs()); 273 EXPECT_EQ(10, cache()->number_of_refs());
52 274
53 controller.SetImageDecodeCache(nullptr); 275 controller()->SetImageDecodeCache(nullptr);
54 EXPECT_EQ(0, cache.number_of_refs()); 276 EXPECT_EQ(0, cache()->number_of_refs());
55 } 277 }
56 278
279 TEST_F(ImageControllerTest, QueueImageDecode) {
280 base::RunLoop run_loop;
281 DecodeClient decode_client;
282 EXPECT_EQ(image()->bounds().width(), 1);
283 ImageController::ImageDecodeRequestId expected_id =
284 controller()->QueueImageDecode(
285 image(),
286 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client),
287 run_loop.QuitClosure()));
288 RunOrTimeout(&run_loop);
289 EXPECT_EQ(expected_id, decode_client.id());
290 }
291
292 TEST_F(ImageControllerTest, QueueImageDecodeMultipleImages) {
293 base::RunLoop run_loop;
294 DecodeClient decode_client1;
295 ImageController::ImageDecodeRequestId expected_id1 =
296 controller()->QueueImageDecode(
297 image(),
298 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client1),
299 base::Bind([] {})));
300 DecodeClient decode_client2;
301 ImageController::ImageDecodeRequestId expected_id2 =
302 controller()->QueueImageDecode(
303 image(),
304 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client2),
305 base::Bind([] {})));
306 DecodeClient decode_client3;
307 ImageController::ImageDecodeRequestId expected_id3 =
308 controller()->QueueImageDecode(
309 image(),
310 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client3),
311 run_loop.QuitClosure()));
312 RunOrTimeout(&run_loop);
313 EXPECT_EQ(expected_id1, decode_client1.id());
314 EXPECT_EQ(expected_id2, decode_client2.id());
315 EXPECT_EQ(expected_id3, decode_client3.id());
316 }
317
318 TEST_F(ImageControllerTest, QueueImageDecodeWithTask) {
319 scoped_refptr<SimpleTask> task(new SimpleTask);
320 cache()->SetTaskToUse(task);
321
322 base::RunLoop run_loop;
323 DecodeClient decode_client;
324 ImageController::ImageDecodeRequestId expected_id =
325 controller()->QueueImageDecode(
326 image(),
327 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client),
328 run_loop.QuitClosure()));
329 RunOrTimeout(&run_loop);
330 EXPECT_EQ(expected_id, decode_client.id());
331 EXPECT_TRUE(task->has_run());
332 EXPECT_TRUE(task->HasCompleted());
333 }
334
335 TEST_F(ImageControllerTest, QueueImageDecodeMultipleImagesSameTask) {
336 scoped_refptr<SimpleTask> task(new SimpleTask);
337 cache()->SetTaskToUse(task);
338
339 base::RunLoop run_loop;
340 DecodeClient decode_client1;
341 ImageController::ImageDecodeRequestId expected_id1 =
342 controller()->QueueImageDecode(
343 image(),
344 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client1),
345 base::Bind([] {})));
346 DecodeClient decode_client2;
347 ImageController::ImageDecodeRequestId expected_id2 =
348 controller()->QueueImageDecode(
349 image(),
350 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client2),
351 base::Bind([] {})));
352 DecodeClient decode_client3;
353 ImageController::ImageDecodeRequestId expected_id3 =
354 controller()->QueueImageDecode(
355 image(),
356 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client3),
357 run_loop.QuitClosure()));
358 RunOrTimeout(&run_loop);
359 EXPECT_EQ(expected_id1, decode_client1.id());
360 EXPECT_EQ(expected_id2, decode_client2.id());
361 EXPECT_EQ(expected_id3, decode_client3.id());
362 EXPECT_TRUE(task->has_run());
363 EXPECT_TRUE(task->HasCompleted());
364 }
365
366 TEST_F(ImageControllerTest, QueueImageDecodeChangeControllerWithTaskQueued) {
367 scoped_refptr<BlockingTask> task_one(new BlockingTask);
368 cache()->SetTaskToUse(task_one);
369
370 DecodeClient decode_client1;
371 ImageController::ImageDecodeRequestId expected_id1 =
372 controller()->QueueImageDecode(
373 image(),
374 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client1),
375 base::Bind([] {})));
376
377 scoped_refptr<BlockingTask> task_two(new BlockingTask);
378 cache()->SetTaskToUse(task_two);
379
380 base::RunLoop run_loop;
381 DecodeClient decode_client2;
382 ImageController::ImageDecodeRequestId expected_id2 =
383 controller()->QueueImageDecode(
384 image(),
385 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client2),
386 run_loop.QuitClosure()));
387
388 task_one->AllowToRun();
389 task_two->AllowToRun();
390 controller()->SetImageDecodeCache(nullptr);
391
392 RunOrTimeout(&run_loop);
393
394 EXPECT_TRUE(task_one->state().IsCanceled() || task_one->HasCompleted());
395 EXPECT_TRUE(task_two->state().IsCanceled() || task_two->HasCompleted());
396 EXPECT_EQ(expected_id1, decode_client1.id());
397 EXPECT_EQ(expected_id2, decode_client2.id());
398 }
399
400 TEST_F(ImageControllerTest, QueueImageDecodeImageAlreadyLocked) {
401 scoped_refptr<SimpleTask> task(new SimpleTask);
402 cache()->SetTaskToUse(task);
403
404 base::RunLoop run_loop1;
405 DecodeClient decode_client1;
406 ImageController::ImageDecodeRequestId expected_id1 =
407 controller()->QueueImageDecode(
408 image(),
409 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client1),
410 run_loop1.QuitClosure()));
411 RunOrTimeout(&run_loop1);
412 EXPECT_EQ(expected_id1, decode_client1.id());
413 EXPECT_TRUE(task->has_run());
414
415 cache()->SetTaskToUse(nullptr);
416 base::RunLoop run_loop2;
417 DecodeClient decode_client2;
418 ImageController::ImageDecodeRequestId expected_id2 =
419 controller()->QueueImageDecode(
420 image(),
421 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client2),
422 run_loop2.QuitClosure()));
423 RunOrTimeout(&run_loop2);
424 EXPECT_EQ(expected_id2, decode_client2.id());
425 }
426
427 TEST_F(ImageControllerTest, QueueImageDecodeLockedImageControllerChange) {
428 scoped_refptr<SimpleTask> task(new SimpleTask);
429 cache()->SetTaskToUse(task);
430
431 base::RunLoop run_loop1;
432 DecodeClient decode_client1;
433 ImageController::ImageDecodeRequestId expected_id1 =
434 controller()->QueueImageDecode(
435 image(),
436 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client1),
437 run_loop1.QuitClosure()));
438 RunOrTimeout(&run_loop1);
439 EXPECT_EQ(expected_id1, decode_client1.id());
440 EXPECT_TRUE(task->has_run());
441 EXPECT_EQ(1, cache()->number_of_refs());
442
443 controller()->SetImageDecodeCache(nullptr);
444 EXPECT_EQ(0, cache()->number_of_refs());
445 }
446
447 } // namespace
57 } // namespace cc 448 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698