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

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

Powered by Google App Engine
This is Rietveld 408576698