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

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

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

Powered by Google App Engine
This is Rietveld 408576698