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.
5 #include "cc/resources/resource_update_controller.h"
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"
25 const int kFlushPeriodFull
= 4;
26 const int kFlushPeriodPartial
= kFlushPeriodFull
;
28 class ResourceUpdateControllerTest
;
30 class WebGraphicsContext3DForUploadTest
: public TestWebGraphicsContext3D
{
32 explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest
* test
)
35 void flush() override
;
36 void shallowFlushCHROMIUM() override
;
37 void texSubImage2D(GLenum target
,
45 const void* pixels
) override
;
47 void getQueryObjectuivEXT(GLuint id
, GLenum pname
, GLuint
* value
) override
;
50 ResourceUpdateControllerTest
* test_
;
53 class ResourceUpdateControllerTest
: public Test
{
55 ResourceUpdateControllerTest()
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) {}
69 ~ResourceUpdateControllerTest() override
{
70 DebugScopedSetImplThreadAndMainThreadBlocked
71 impl_thread_and_main_thread_blocked(&proxy_
);
72 resource_manager_
->ClearAllMemory(resource_provider_
.get());
77 // Check for back-to-back flushes.
78 EXPECT_EQ(0, num_consecutive_flushes_
) << "Back-to-back flushes detected.";
80 num_dangling_uploads_
= 0;
81 num_consecutive_flushes_
++;
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.";
91 EXPECT_LT(num_dangling_uploads_
, kFlushPeriodPartial
)
92 << "Too many consecutive partial uploads detected.";
95 num_consecutive_flushes_
= 0;
96 num_dangling_uploads_
++;
100 bool IsQueryResultAvailable() {
101 if (!query_results_available_
)
104 query_results_available_
--;
109 void SetUp() override
{
110 bitmap_
.allocN32Pixels(300, 150);
112 for (int i
= 0; i
< 4; i
++) {
113 textures_
[i
] = PrioritizedResource::Create(resource_manager_
.get(),
117 set_request_priority(PriorityCalculator::VisiblePriority(true));
119 resource_manager_
->PrioritizeTextures();
121 output_surface_
= FakeOutputSurface::Create3d(
122 scoped_ptr
<TestWebGraphicsContext3D
>(
123 new WebGraphicsContext3DForUploadTest(this)));
124 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
126 shared_bitmap_manager_
.reset(new TestSharedBitmapManager());
127 resource_provider_
= ResourceProvider::Create(output_surface_
.get(),
128 shared_bitmap_manager_
.get(),
136 void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count
,
138 full_upload_count_expected_
+= count
;
139 total_upload_count_expected_
+= count
;
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
);
148 void AppendFullUploadsToUpdateQueue(int count
) {
149 AppendFullUploadsOfIndexedTextureToUpdateQueue(count
, 0);
152 void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count
,
154 partial_count_expected_
+= count
;
155 total_upload_count_expected_
+= count
;
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
);
164 void AppendPartialUploadsToUpdateQueue(int count
) {
165 AppendPartialUploadsOfIndexedTextureToUpdateQueue(count
, 0);
168 void SetMaxUploadCountPerUpdate(int count
) {
169 max_upload_count_per_update_
= count
;
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(),
179 resource_provider_
.get());
180 update_controller
->Finalize();
183 void MakeQueryResultAvailable() { query_results_available_
++; }
186 // Classes required to interact and test the ResourceUpdateController
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_
;
196 int query_results_available_
;
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_
;
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_
;
211 void WebGraphicsContext3DForUploadTest::flush() { test_
->OnFlush(); }
213 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() {
217 void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target
,
225 const void* pixels
) {
229 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id
,
232 if (pname
== GL_QUERY_RESULT_AVAILABLE_EXT
)
233 *params
= test_
->IsQueryResultAvailable();
236 // ZERO UPLOADS TESTS
237 TEST_F(ResourceUpdateControllerTest
, ZeroUploads
) {
238 AppendFullUploadsToUpdateQueue(0);
239 AppendPartialUploadsToUpdateQueue(0);
242 EXPECT_EQ(0, num_total_flushes_
);
243 EXPECT_EQ(0, num_total_uploads_
);
247 TEST_F(ResourceUpdateControllerTest
, OneFullUpload
) {
248 AppendFullUploadsToUpdateQueue(1);
249 AppendPartialUploadsToUpdateQueue(0);
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.";
258 TEST_F(ResourceUpdateControllerTest
, OnePartialUpload
) {
259 AppendFullUploadsToUpdateQueue(0);
260 AppendPartialUploadsToUpdateQueue(1);
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.";
269 TEST_F(ResourceUpdateControllerTest
, OneFullOnePartialUpload
) {
270 AppendFullUploadsToUpdateQueue(1);
271 AppendPartialUploadsToUpdateQueue(1);
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.";
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
;
285 const int partial_upload_flush_multipler
= 11;
286 const int partial_count
=
287 partial_upload_flush_multipler
* kFlushPeriodPartial
;
289 TEST_F(ResourceUpdateControllerTest
, ManyFullUploads
) {
290 AppendFullUploadsToUpdateQueue(full_count
);
291 AppendPartialUploadsToUpdateQueue(0);
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.";
300 TEST_F(ResourceUpdateControllerTest
, ManyPartialUploads
) {
301 AppendFullUploadsToUpdateQueue(0);
302 AppendPartialUploadsToUpdateQueue(partial_count
);
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.";
311 TEST_F(ResourceUpdateControllerTest
, ManyFullManyPartialUploads
) {
312 AppendFullUploadsToUpdateQueue(full_count
);
313 AppendPartialUploadsToUpdateQueue(partial_count
);
316 EXPECT_EQ(full_upload_flush_multipler
+ partial_upload_flush_multipler
,
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.";
323 class FakeResourceUpdateControllerClient
324 : public ResourceUpdateControllerClient
{
326 FakeResourceUpdateControllerClient() { Reset(); }
327 void Reset() { ready_to_finalize_called_
= false; }
328 bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_
; }
330 void ReadyToFinalizeTextureUpdates() override
{
331 ready_to_finalize_called_
= true;
335 bool ready_to_finalize_called_
;
338 class FakeResourceUpdateController
: public ResourceUpdateController
{
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
));
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
;
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_
;
359 void SetUpdateMoreTexturesSize(size_t size
) {
360 update_more_textures_size_
= size
;
362 size_t UpdateMoreTexturesSize() const override
{
363 return update_more_textures_size_
;
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) {}
376 ResourceProvider
* resource_provider_
;
377 base::TimeTicks now_
;
378 base::TimeDelta update_textures_time_
;
379 size_t update_more_textures_size_
;
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();
389 TEST_F(ResourceUpdateControllerTest
, UpdateMoreTextures
) {
390 FakeResourceUpdateControllerClient client
;
391 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
392 new base::TestSimpleTaskRunner
;
394 SetMaxUploadCountPerUpdate(1);
395 AppendFullUploadsToUpdateQueue(3);
396 AppendPartialUploadsToUpdateQueue(0);
398 DebugScopedSetImplThreadAndMainThreadBlocked
399 impl_thread_and_main_thread_blocked(&proxy_
);
400 scoped_ptr
<FakeResourceUpdateController
> controller(
401 FakeResourceUpdateController::Create(&client
,
404 resource_provider_
.get()));
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());
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_
);
422 // Complete one upload.
423 MakeQueryResultAvailable();
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_
);
436 TEST_F(ResourceUpdateControllerTest
, NoMoreUpdates
) {
437 FakeResourceUpdateControllerClient client
;
438 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
439 new base::TestSimpleTaskRunner
;
441 SetMaxUploadCountPerUpdate(1);
442 AppendFullUploadsToUpdateQueue(2);
443 AppendPartialUploadsToUpdateQueue(0);
445 DebugScopedSetImplThreadAndMainThreadBlocked
446 impl_thread_and_main_thread_blocked(&proxy_
);
447 scoped_ptr
<FakeResourceUpdateController
> controller(
448 FakeResourceUpdateController::Create(&client
,
451 resource_provider_
.get()));
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_
);
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));
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_
);
477 TEST_F(ResourceUpdateControllerTest
, UpdatesCompleteInFiniteTime
) {
478 FakeResourceUpdateControllerClient client
;
479 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
480 new base::TestSimpleTaskRunner
;
482 SetMaxUploadCountPerUpdate(1);
483 AppendFullUploadsToUpdateQueue(2);
484 AppendPartialUploadsToUpdateQueue(0);
486 DebugScopedSetImplThreadAndMainThreadBlocked
487 impl_thread_and_main_thread_blocked(&proxy_
);
488 scoped_ptr
<FakeResourceUpdateController
> controller(
489 FakeResourceUpdateController::Create(&client
,
492 resource_provider_
.get()));
494 controller
->SetNow(controller
->Now() + base::TimeDelta::FromMilliseconds(1));
495 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500));
496 controller
->SetUpdateMoreTexturesSize(1);
498 for (int i
= 0; i
< 100; i
++) {
499 if (client
.ReadyToFinalizeCalled())
502 // Not enough time for any updates.
503 controller
->PerformMoreUpdates(controller
->Now() +
504 base::TimeDelta::FromMilliseconds(400));
506 if (task_runner
->HasPendingTask())
507 RunPendingTask(task_runner
.get(), controller
.get());
510 EXPECT_FALSE(task_runner
->HasPendingTask());
511 EXPECT_TRUE(client
.ReadyToFinalizeCalled());
512 EXPECT_EQ(2, num_total_uploads_
);