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

Side by Side Diff: cc/tiles/image_controller_unittest.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.cc ('k') | cc/tiles/image_decode_cache.h » ('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 "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 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());
55 } 276 }
56 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, QueueImageDecodeImageAlreadyLocked) {
400 scoped_refptr<SimpleTask> task(new SimpleTask);
401 cache()->SetTaskToUse(task);
402
403 base::RunLoop run_loop1;
404 DecodeClient decode_client1;
405 ImageController::ImageDecodeRequestId expected_id1 =
406 controller()->QueueImageDecode(
407 image(),
408 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client1),
409 run_loop1.QuitClosure()));
410 RunOrTimeout(&run_loop1);
411 EXPECT_EQ(expected_id1, decode_client1.id());
412 EXPECT_TRUE(task->has_run());
413
414 cache()->SetTaskToUse(nullptr);
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
426 TEST_F(ImageControllerTest, QueueImageDecodeLockedImageControllerChange) {
427 scoped_refptr<SimpleTask> task(new SimpleTask);
428 cache()->SetTaskToUse(task);
429
430 base::RunLoop run_loop1;
431 DecodeClient decode_client1;
432 ImageController::ImageDecodeRequestId expected_id1 =
433 controller()->QueueImageDecode(
434 image(),
435 base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client1),
436 run_loop1.QuitClosure()));
437 RunOrTimeout(&run_loop1);
438 EXPECT_EQ(expected_id1, decode_client1.id());
439 EXPECT_TRUE(task->has_run());
440 EXPECT_EQ(1, cache()->number_of_refs());
441
442 controller()->SetImageDecodeCache(nullptr);
443 EXPECT_EQ(0, cache()->number_of_refs());
444 }
445
446 } // namespace
57 } // namespace cc 447 } // namespace cc
OLDNEW
« no previous file with comments | « cc/tiles/image_controller.cc ('k') | cc/tiles/image_decode_cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698