OLD | NEW |
| (Empty) |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/resources/resource_update_controller.h" | |
6 | |
7 #include "base/test/test_simple_task_runner.h" | |
8 #include "cc/resources/prioritized_resource_manager.h" | |
9 #include "cc/test/fake_output_surface.h" | |
10 #include "cc/test/fake_output_surface_client.h" | |
11 #include "cc/test/fake_proxy.h" | |
12 #include "cc/test/scheduler_test_common.h" | |
13 #include "cc/test/test_shared_bitmap_manager.h" | |
14 #include "cc/test/test_web_graphics_context_3d.h" | |
15 #include "cc/test/tiled_layer_test_common.h" | |
16 #include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "third_party/khronos/GLES2/gl2ext.h" | |
19 | |
20 using testing::Test; | |
21 | |
22 namespace cc { | |
23 namespace { | |
24 | |
25 const int kFlushPeriodFull = 4; | |
26 const int kFlushPeriodPartial = kFlushPeriodFull; | |
27 | |
28 class ResourceUpdateControllerTest; | |
29 | |
30 class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D { | |
31 public: | |
32 explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test) | |
33 : test_(test) {} | |
34 | |
35 void flush() override; | |
36 void shallowFlushCHROMIUM() override; | |
37 void texSubImage2D(GLenum target, | |
38 GLint level, | |
39 GLint xoffset, | |
40 GLint yoffset, | |
41 GLsizei width, | |
42 GLsizei height, | |
43 GLenum format, | |
44 GLenum type, | |
45 const void* pixels) override; | |
46 | |
47 void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value) override; | |
48 | |
49 private: | |
50 ResourceUpdateControllerTest* test_; | |
51 }; | |
52 | |
53 class ResourceUpdateControllerTest : public Test { | |
54 public: | |
55 ResourceUpdateControllerTest() | |
56 : proxy_(), | |
57 queue_(make_scoped_ptr(new ResourceUpdateQueue)), | |
58 resource_manager_(PrioritizedResourceManager::Create(&proxy_)), | |
59 query_results_available_(0), | |
60 full_upload_count_expected_(0), | |
61 partial_count_expected_(0), | |
62 total_upload_count_expected_(0), | |
63 max_upload_count_per_update_(0), | |
64 num_consecutive_flushes_(0), | |
65 num_dangling_uploads_(0), | |
66 num_total_uploads_(0), | |
67 num_total_flushes_(0) {} | |
68 | |
69 ~ResourceUpdateControllerTest() override { | |
70 DebugScopedSetImplThreadAndMainThreadBlocked | |
71 impl_thread_and_main_thread_blocked(&proxy_); | |
72 resource_manager_->ClearAllMemory(resource_provider_.get()); | |
73 } | |
74 | |
75 public: | |
76 void OnFlush() { | |
77 // Check for back-to-back flushes. | |
78 EXPECT_EQ(0, num_consecutive_flushes_) << "Back-to-back flushes detected."; | |
79 | |
80 num_dangling_uploads_ = 0; | |
81 num_consecutive_flushes_++; | |
82 num_total_flushes_++; | |
83 } | |
84 | |
85 void OnUpload() { | |
86 // Check for too many consecutive uploads | |
87 if (num_total_uploads_ < full_upload_count_expected_) { | |
88 EXPECT_LT(num_dangling_uploads_, kFlushPeriodFull) | |
89 << "Too many consecutive full uploads detected."; | |
90 } else { | |
91 EXPECT_LT(num_dangling_uploads_, kFlushPeriodPartial) | |
92 << "Too many consecutive partial uploads detected."; | |
93 } | |
94 | |
95 num_consecutive_flushes_ = 0; | |
96 num_dangling_uploads_++; | |
97 num_total_uploads_++; | |
98 } | |
99 | |
100 bool IsQueryResultAvailable() { | |
101 if (!query_results_available_) | |
102 return false; | |
103 | |
104 query_results_available_--; | |
105 return true; | |
106 } | |
107 | |
108 protected: | |
109 void SetUp() override { | |
110 bitmap_.allocN32Pixels(300, 150); | |
111 | |
112 for (int i = 0; i < 4; i++) { | |
113 textures_[i] = PrioritizedResource::Create(resource_manager_.get(), | |
114 gfx::Size(300, 150), | |
115 RGBA_8888); | |
116 textures_[i]-> | |
117 set_request_priority(PriorityCalculator::VisiblePriority(true)); | |
118 } | |
119 resource_manager_->PrioritizeTextures(); | |
120 | |
121 output_surface_ = FakeOutputSurface::Create3d( | |
122 scoped_ptr<TestWebGraphicsContext3D>( | |
123 new WebGraphicsContext3DForUploadTest(this))); | |
124 CHECK(output_surface_->BindToClient(&output_surface_client_)); | |
125 | |
126 shared_bitmap_manager_.reset(new TestSharedBitmapManager()); | |
127 resource_provider_ = ResourceProvider::Create(output_surface_.get(), | |
128 shared_bitmap_manager_.get(), | |
129 NULL, | |
130 NULL, | |
131 0, | |
132 false, | |
133 1); | |
134 } | |
135 | |
136 void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count, | |
137 int texture_index) { | |
138 full_upload_count_expected_ += count; | |
139 total_upload_count_expected_ += count; | |
140 | |
141 const gfx::Rect rect(0, 0, 300, 150); | |
142 const ResourceUpdate upload = ResourceUpdate::Create( | |
143 textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d()); | |
144 for (int i = 0; i < count; i++) | |
145 queue_->AppendFullUpload(upload); | |
146 } | |
147 | |
148 void AppendFullUploadsToUpdateQueue(int count) { | |
149 AppendFullUploadsOfIndexedTextureToUpdateQueue(count, 0); | |
150 } | |
151 | |
152 void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count, | |
153 int texture_index) { | |
154 partial_count_expected_ += count; | |
155 total_upload_count_expected_ += count; | |
156 | |
157 const gfx::Rect rect(0, 0, 100, 100); | |
158 const ResourceUpdate upload = ResourceUpdate::Create( | |
159 textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d()); | |
160 for (int i = 0; i < count; i++) | |
161 queue_->AppendPartialUpload(upload); | |
162 } | |
163 | |
164 void AppendPartialUploadsToUpdateQueue(int count) { | |
165 AppendPartialUploadsOfIndexedTextureToUpdateQueue(count, 0); | |
166 } | |
167 | |
168 void SetMaxUploadCountPerUpdate(int count) { | |
169 max_upload_count_per_update_ = count; | |
170 } | |
171 | |
172 void UpdateTextures() { | |
173 DebugScopedSetImplThreadAndMainThreadBlocked | |
174 impl_thread_and_main_thread_blocked(&proxy_); | |
175 scoped_ptr<ResourceUpdateController> update_controller = | |
176 ResourceUpdateController::Create(NULL, | |
177 proxy_.ImplThreadTaskRunner(), | |
178 queue_.Pass(), | |
179 resource_provider_.get()); | |
180 update_controller->Finalize(); | |
181 } | |
182 | |
183 void MakeQueryResultAvailable() { query_results_available_++; } | |
184 | |
185 protected: | |
186 // Classes required to interact and test the ResourceUpdateController | |
187 FakeProxy proxy_; | |
188 FakeOutputSurfaceClient output_surface_client_; | |
189 scoped_ptr<OutputSurface> output_surface_; | |
190 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; | |
191 scoped_ptr<ResourceProvider> resource_provider_; | |
192 scoped_ptr<ResourceUpdateQueue> queue_; | |
193 scoped_ptr<PrioritizedResource> textures_[4]; | |
194 scoped_ptr<PrioritizedResourceManager> resource_manager_; | |
195 SkBitmap bitmap_; | |
196 int query_results_available_; | |
197 | |
198 // Properties / expectations of this test | |
199 int full_upload_count_expected_; | |
200 int partial_count_expected_; | |
201 int total_upload_count_expected_; | |
202 int max_upload_count_per_update_; | |
203 | |
204 // Dynamic properties of this test | |
205 int num_consecutive_flushes_; | |
206 int num_dangling_uploads_; | |
207 int num_total_uploads_; | |
208 int num_total_flushes_; | |
209 }; | |
210 | |
211 void WebGraphicsContext3DForUploadTest::flush() { test_->OnFlush(); } | |
212 | |
213 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() { | |
214 test_->OnFlush(); | |
215 } | |
216 | |
217 void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target, | |
218 GLint level, | |
219 GLint xoffset, | |
220 GLint yoffset, | |
221 GLsizei width, | |
222 GLsizei height, | |
223 GLenum format, | |
224 GLenum type, | |
225 const void* pixels) { | |
226 test_->OnUpload(); | |
227 } | |
228 | |
229 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id, | |
230 GLenum pname, | |
231 GLuint* params) { | |
232 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT) | |
233 *params = test_->IsQueryResultAvailable(); | |
234 } | |
235 | |
236 // ZERO UPLOADS TESTS | |
237 TEST_F(ResourceUpdateControllerTest, ZeroUploads) { | |
238 AppendFullUploadsToUpdateQueue(0); | |
239 AppendPartialUploadsToUpdateQueue(0); | |
240 UpdateTextures(); | |
241 | |
242 EXPECT_EQ(0, num_total_flushes_); | |
243 EXPECT_EQ(0, num_total_uploads_); | |
244 } | |
245 | |
246 // ONE UPLOAD TESTS | |
247 TEST_F(ResourceUpdateControllerTest, OneFullUpload) { | |
248 AppendFullUploadsToUpdateQueue(1); | |
249 AppendPartialUploadsToUpdateQueue(0); | |
250 UpdateTextures(); | |
251 | |
252 EXPECT_EQ(1, num_total_flushes_); | |
253 EXPECT_EQ(1, num_total_uploads_); | |
254 EXPECT_EQ(0, num_dangling_uploads_) | |
255 << "Last upload wasn't followed by a flush."; | |
256 } | |
257 | |
258 TEST_F(ResourceUpdateControllerTest, OnePartialUpload) { | |
259 AppendFullUploadsToUpdateQueue(0); | |
260 AppendPartialUploadsToUpdateQueue(1); | |
261 UpdateTextures(); | |
262 | |
263 EXPECT_EQ(1, num_total_flushes_); | |
264 EXPECT_EQ(1, num_total_uploads_); | |
265 EXPECT_EQ(0, num_dangling_uploads_) | |
266 << "Last upload wasn't followed by a flush."; | |
267 } | |
268 | |
269 TEST_F(ResourceUpdateControllerTest, OneFullOnePartialUpload) { | |
270 AppendFullUploadsToUpdateQueue(1); | |
271 AppendPartialUploadsToUpdateQueue(1); | |
272 UpdateTextures(); | |
273 | |
274 EXPECT_EQ(1, num_total_flushes_); | |
275 EXPECT_EQ(2, num_total_uploads_); | |
276 EXPECT_EQ(0, num_dangling_uploads_) | |
277 << "Last upload wasn't followed by a flush."; | |
278 } | |
279 | |
280 // This class of tests upload a number of textures that is a multiple | |
281 // of the flush period. | |
282 const int full_upload_flush_multipler = 7; | |
283 const int full_count = full_upload_flush_multipler * kFlushPeriodFull; | |
284 | |
285 const int partial_upload_flush_multipler = 11; | |
286 const int partial_count = | |
287 partial_upload_flush_multipler * kFlushPeriodPartial; | |
288 | |
289 TEST_F(ResourceUpdateControllerTest, ManyFullUploads) { | |
290 AppendFullUploadsToUpdateQueue(full_count); | |
291 AppendPartialUploadsToUpdateQueue(0); | |
292 UpdateTextures(); | |
293 | |
294 EXPECT_EQ(full_upload_flush_multipler, num_total_flushes_); | |
295 EXPECT_EQ(full_count, num_total_uploads_); | |
296 EXPECT_EQ(0, num_dangling_uploads_) | |
297 << "Last upload wasn't followed by a flush."; | |
298 } | |
299 | |
300 TEST_F(ResourceUpdateControllerTest, ManyPartialUploads) { | |
301 AppendFullUploadsToUpdateQueue(0); | |
302 AppendPartialUploadsToUpdateQueue(partial_count); | |
303 UpdateTextures(); | |
304 | |
305 EXPECT_EQ(partial_upload_flush_multipler, num_total_flushes_); | |
306 EXPECT_EQ(partial_count, num_total_uploads_); | |
307 EXPECT_EQ(0, num_dangling_uploads_) | |
308 << "Last upload wasn't followed by a flush."; | |
309 } | |
310 | |
311 TEST_F(ResourceUpdateControllerTest, ManyFullManyPartialUploads) { | |
312 AppendFullUploadsToUpdateQueue(full_count); | |
313 AppendPartialUploadsToUpdateQueue(partial_count); | |
314 UpdateTextures(); | |
315 | |
316 EXPECT_EQ(full_upload_flush_multipler + partial_upload_flush_multipler, | |
317 num_total_flushes_); | |
318 EXPECT_EQ(full_count + partial_count, num_total_uploads_); | |
319 EXPECT_EQ(0, num_dangling_uploads_) | |
320 << "Last upload wasn't followed by a flush."; | |
321 } | |
322 | |
323 class FakeResourceUpdateControllerClient | |
324 : public ResourceUpdateControllerClient { | |
325 public: | |
326 FakeResourceUpdateControllerClient() { Reset(); } | |
327 void Reset() { ready_to_finalize_called_ = false; } | |
328 bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_; } | |
329 | |
330 void ReadyToFinalizeTextureUpdates() override { | |
331 ready_to_finalize_called_ = true; | |
332 } | |
333 | |
334 protected: | |
335 bool ready_to_finalize_called_; | |
336 }; | |
337 | |
338 class FakeResourceUpdateController : public ResourceUpdateController { | |
339 public: | |
340 static scoped_ptr<FakeResourceUpdateController> Create( | |
341 ResourceUpdateControllerClient* client, | |
342 base::TestSimpleTaskRunner* task_runner, | |
343 scoped_ptr<ResourceUpdateQueue> queue, | |
344 ResourceProvider* resource_provider) { | |
345 return make_scoped_ptr(new FakeResourceUpdateController( | |
346 client, task_runner, queue.Pass(), resource_provider)); | |
347 } | |
348 | |
349 void SetNow(base::TimeTicks time) { now_ = time; } | |
350 base::TimeTicks Now() const { return now_; } | |
351 void SetUpdateTextureTime(base::TimeDelta time) { | |
352 update_textures_time_ = time; | |
353 } | |
354 base::TimeTicks UpdateMoreTexturesCompletionTime() override { | |
355 size_t total_updates = | |
356 resource_provider_->NumBlockingUploads() + update_more_textures_size_; | |
357 return now_ + total_updates * update_textures_time_; | |
358 } | |
359 void SetUpdateMoreTexturesSize(size_t size) { | |
360 update_more_textures_size_ = size; | |
361 } | |
362 size_t UpdateMoreTexturesSize() const override { | |
363 return update_more_textures_size_; | |
364 } | |
365 | |
366 protected: | |
367 FakeResourceUpdateController(ResourceUpdateControllerClient* client, | |
368 base::TestSimpleTaskRunner* task_runner, | |
369 scoped_ptr<ResourceUpdateQueue> queue, | |
370 ResourceProvider* resource_provider) | |
371 : ResourceUpdateController( | |
372 client, task_runner, queue.Pass(), resource_provider), | |
373 resource_provider_(resource_provider), | |
374 update_more_textures_size_(0) {} | |
375 | |
376 ResourceProvider* resource_provider_; | |
377 base::TimeTicks now_; | |
378 base::TimeDelta update_textures_time_; | |
379 size_t update_more_textures_size_; | |
380 }; | |
381 | |
382 static void RunPendingTask(base::TestSimpleTaskRunner* task_runner, | |
383 FakeResourceUpdateController* controller) { | |
384 EXPECT_TRUE(task_runner->HasPendingTask()); | |
385 controller->SetNow(controller->Now() + task_runner->NextPendingTaskDelay()); | |
386 task_runner->RunPendingTasks(); | |
387 } | |
388 | |
389 TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) { | |
390 FakeResourceUpdateControllerClient client; | |
391 scoped_refptr<base::TestSimpleTaskRunner> task_runner = | |
392 new base::TestSimpleTaskRunner; | |
393 | |
394 SetMaxUploadCountPerUpdate(1); | |
395 AppendFullUploadsToUpdateQueue(3); | |
396 AppendPartialUploadsToUpdateQueue(0); | |
397 | |
398 DebugScopedSetImplThreadAndMainThreadBlocked | |
399 impl_thread_and_main_thread_blocked(&proxy_); | |
400 scoped_ptr<FakeResourceUpdateController> controller( | |
401 FakeResourceUpdateController::Create(&client, | |
402 task_runner.get(), | |
403 queue_.Pass(), | |
404 resource_provider_.get())); | |
405 | |
406 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1)); | |
407 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); | |
408 controller->SetUpdateMoreTexturesSize(1); | |
409 // Not enough time for any updates. | |
410 controller->PerformMoreUpdates(controller->Now() + | |
411 base::TimeDelta::FromMilliseconds(90)); | |
412 EXPECT_FALSE(task_runner->HasPendingTask()); | |
413 | |
414 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); | |
415 controller->SetUpdateMoreTexturesSize(1); | |
416 // Only enough time for 1 update. | |
417 controller->PerformMoreUpdates(controller->Now() + | |
418 base::TimeDelta::FromMilliseconds(120)); | |
419 EXPECT_FALSE(task_runner->HasPendingTask()); | |
420 EXPECT_EQ(1, num_total_uploads_); | |
421 | |
422 // Complete one upload. | |
423 MakeQueryResultAvailable(); | |
424 | |
425 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); | |
426 controller->SetUpdateMoreTexturesSize(1); | |
427 // Enough time for 2 updates. | |
428 controller->PerformMoreUpdates(controller->Now() + | |
429 base::TimeDelta::FromMilliseconds(220)); | |
430 RunPendingTask(task_runner.get(), controller.get()); | |
431 EXPECT_FALSE(task_runner->HasPendingTask()); | |
432 EXPECT_TRUE(client.ReadyToFinalizeCalled()); | |
433 EXPECT_EQ(3, num_total_uploads_); | |
434 } | |
435 | |
436 TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) { | |
437 FakeResourceUpdateControllerClient client; | |
438 scoped_refptr<base::TestSimpleTaskRunner> task_runner = | |
439 new base::TestSimpleTaskRunner; | |
440 | |
441 SetMaxUploadCountPerUpdate(1); | |
442 AppendFullUploadsToUpdateQueue(2); | |
443 AppendPartialUploadsToUpdateQueue(0); | |
444 | |
445 DebugScopedSetImplThreadAndMainThreadBlocked | |
446 impl_thread_and_main_thread_blocked(&proxy_); | |
447 scoped_ptr<FakeResourceUpdateController> controller( | |
448 FakeResourceUpdateController::Create(&client, | |
449 task_runner.get(), | |
450 queue_.Pass(), | |
451 resource_provider_.get())); | |
452 | |
453 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1)); | |
454 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); | |
455 controller->SetUpdateMoreTexturesSize(1); | |
456 // Enough time for 3 updates but only 2 necessary. | |
457 controller->PerformMoreUpdates(controller->Now() + | |
458 base::TimeDelta::FromMilliseconds(310)); | |
459 RunPendingTask(task_runner.get(), controller.get()); | |
460 EXPECT_FALSE(task_runner->HasPendingTask()); | |
461 EXPECT_TRUE(client.ReadyToFinalizeCalled()); | |
462 EXPECT_EQ(2, num_total_uploads_); | |
463 | |
464 client.Reset(); | |
465 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100)); | |
466 controller->SetUpdateMoreTexturesSize(1); | |
467 // Enough time for updates but no more updates left. | |
468 controller->PerformMoreUpdates(controller->Now() + | |
469 base::TimeDelta::FromMilliseconds(310)); | |
470 | |
471 // ReadyToFinalizeTextureUpdates should only be called once. | |
472 EXPECT_FALSE(task_runner->HasPendingTask()); | |
473 EXPECT_FALSE(client.ReadyToFinalizeCalled()); | |
474 EXPECT_EQ(2, num_total_uploads_); | |
475 } | |
476 | |
477 TEST_F(ResourceUpdateControllerTest, UpdatesCompleteInFiniteTime) { | |
478 FakeResourceUpdateControllerClient client; | |
479 scoped_refptr<base::TestSimpleTaskRunner> task_runner = | |
480 new base::TestSimpleTaskRunner; | |
481 | |
482 SetMaxUploadCountPerUpdate(1); | |
483 AppendFullUploadsToUpdateQueue(2); | |
484 AppendPartialUploadsToUpdateQueue(0); | |
485 | |
486 DebugScopedSetImplThreadAndMainThreadBlocked | |
487 impl_thread_and_main_thread_blocked(&proxy_); | |
488 scoped_ptr<FakeResourceUpdateController> controller( | |
489 FakeResourceUpdateController::Create(&client, | |
490 task_runner.get(), | |
491 queue_.Pass(), | |
492 resource_provider_.get())); | |
493 | |
494 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1)); | |
495 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500)); | |
496 controller->SetUpdateMoreTexturesSize(1); | |
497 | |
498 for (int i = 0; i < 100; i++) { | |
499 if (client.ReadyToFinalizeCalled()) | |
500 break; | |
501 | |
502 // Not enough time for any updates. | |
503 controller->PerformMoreUpdates(controller->Now() + | |
504 base::TimeDelta::FromMilliseconds(400)); | |
505 | |
506 if (task_runner->HasPendingTask()) | |
507 RunPendingTask(task_runner.get(), controller.get()); | |
508 } | |
509 | |
510 EXPECT_FALSE(task_runner->HasPendingTask()); | |
511 EXPECT_TRUE(client.ReadyToFinalizeCalled()); | |
512 EXPECT_EQ(2, num_total_uploads_); | |
513 } | |
514 | |
515 } // namespace | |
516 } // namespace cc | |
OLD | NEW |