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/fake_resource_provider.h"
13 #include "cc/test/scheduler_test_common.h"
14 #include "cc/test/test_shared_bitmap_manager.h"
15 #include "cc/test/test_web_graphics_context_3d.h"
16 #include "cc/test/tiled_layer_test_common.h"
17 #include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/khronos/GLES2/gl2ext.h"
26 const int kFlushPeriodFull
= 4;
27 const int kFlushPeriodPartial
= kFlushPeriodFull
;
29 class ResourceUpdateControllerTest
;
31 class WebGraphicsContext3DForUploadTest
: public TestWebGraphicsContext3D
{
33 explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest
* test
)
36 void flush() override
;
37 void shallowFlushCHROMIUM() override
;
38 void texSubImage2D(GLenum target
,
46 const void* pixels
) override
;
48 void getQueryObjectuivEXT(GLuint id
, GLenum pname
, GLuint
* value
) override
;
51 ResourceUpdateControllerTest
* test_
;
54 class ResourceUpdateControllerTest
: public Test
{
56 ResourceUpdateControllerTest()
58 queue_(make_scoped_ptr(new ResourceUpdateQueue
)),
59 resource_manager_(PrioritizedResourceManager::Create(&proxy_
)),
60 query_results_available_(0),
61 full_upload_count_expected_(0),
62 partial_count_expected_(0),
63 total_upload_count_expected_(0),
64 max_upload_count_per_update_(0),
65 num_consecutive_flushes_(0),
66 num_dangling_uploads_(0),
67 num_total_uploads_(0),
68 num_total_flushes_(0) {}
70 ~ResourceUpdateControllerTest() override
{
71 DebugScopedSetImplThreadAndMainThreadBlocked
72 impl_thread_and_main_thread_blocked(&proxy_
);
73 resource_manager_
->ClearAllMemory(resource_provider_
.get());
78 // Check for back-to-back flushes.
79 EXPECT_EQ(0, num_consecutive_flushes_
) << "Back-to-back flushes detected.";
81 num_dangling_uploads_
= 0;
82 num_consecutive_flushes_
++;
87 // Check for too many consecutive uploads
88 if (num_total_uploads_
< full_upload_count_expected_
) {
89 EXPECT_LT(num_dangling_uploads_
, kFlushPeriodFull
)
90 << "Too many consecutive full uploads detected.";
92 EXPECT_LT(num_dangling_uploads_
, kFlushPeriodPartial
)
93 << "Too many consecutive partial uploads detected.";
96 num_consecutive_flushes_
= 0;
97 num_dangling_uploads_
++;
101 bool IsQueryResultAvailable() {
102 if (!query_results_available_
)
105 query_results_available_
--;
110 void SetUp() override
{
111 bitmap_
.allocN32Pixels(300, 150);
113 for (int i
= 0; i
< 4; i
++) {
114 textures_
[i
] = PrioritizedResource::Create(resource_manager_
.get(),
118 set_request_priority(PriorityCalculator::VisiblePriority(true));
120 resource_manager_
->PrioritizeTextures();
122 output_surface_
= FakeOutputSurface::Create3d(
123 scoped_ptr
<TestWebGraphicsContext3D
>(
124 new WebGraphicsContext3DForUploadTest(this)));
125 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
127 shared_bitmap_manager_
.reset(new TestSharedBitmapManager());
128 resource_provider_
= FakeResourceProvider::Create(
129 output_surface_
.get(), shared_bitmap_manager_
.get());
132 void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count
,
134 full_upload_count_expected_
+= count
;
135 total_upload_count_expected_
+= count
;
137 const gfx::Rect
rect(0, 0, 300, 150);
138 const ResourceUpdate upload
= ResourceUpdate::Create(
139 textures_
[texture_index
].get(), &bitmap_
, rect
, rect
, gfx::Vector2d());
140 for (int i
= 0; i
< count
; i
++)
141 queue_
->AppendFullUpload(upload
);
144 void AppendFullUploadsToUpdateQueue(int count
) {
145 AppendFullUploadsOfIndexedTextureToUpdateQueue(count
, 0);
148 void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count
,
150 partial_count_expected_
+= count
;
151 total_upload_count_expected_
+= count
;
153 const gfx::Rect
rect(0, 0, 100, 100);
154 const ResourceUpdate upload
= ResourceUpdate::Create(
155 textures_
[texture_index
].get(), &bitmap_
, rect
, rect
, gfx::Vector2d());
156 for (int i
= 0; i
< count
; i
++)
157 queue_
->AppendPartialUpload(upload
);
160 void AppendPartialUploadsToUpdateQueue(int count
) {
161 AppendPartialUploadsOfIndexedTextureToUpdateQueue(count
, 0);
164 void SetMaxUploadCountPerUpdate(int count
) {
165 max_upload_count_per_update_
= count
;
168 void UpdateTextures() {
169 DebugScopedSetImplThreadAndMainThreadBlocked
170 impl_thread_and_main_thread_blocked(&proxy_
);
171 scoped_ptr
<ResourceUpdateController
> update_controller
=
172 ResourceUpdateController::Create(NULL
,
173 proxy_
.ImplThreadTaskRunner(),
175 resource_provider_
.get());
176 update_controller
->Finalize();
179 void MakeQueryResultAvailable() { query_results_available_
++; }
182 // Classes required to interact and test the ResourceUpdateController
184 FakeOutputSurfaceClient output_surface_client_
;
185 scoped_ptr
<OutputSurface
> output_surface_
;
186 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
187 scoped_ptr
<ResourceProvider
> resource_provider_
;
188 scoped_ptr
<ResourceUpdateQueue
> queue_
;
189 scoped_ptr
<PrioritizedResource
> textures_
[4];
190 scoped_ptr
<PrioritizedResourceManager
> resource_manager_
;
192 int query_results_available_
;
194 // Properties / expectations of this test
195 int full_upload_count_expected_
;
196 int partial_count_expected_
;
197 int total_upload_count_expected_
;
198 int max_upload_count_per_update_
;
200 // Dynamic properties of this test
201 int num_consecutive_flushes_
;
202 int num_dangling_uploads_
;
203 int num_total_uploads_
;
204 int num_total_flushes_
;
207 void WebGraphicsContext3DForUploadTest::flush() { test_
->OnFlush(); }
209 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() {
213 void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target
,
221 const void* pixels
) {
225 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id
,
228 if (pname
== GL_QUERY_RESULT_AVAILABLE_EXT
)
229 *params
= test_
->IsQueryResultAvailable();
232 // ZERO UPLOADS TESTS
233 TEST_F(ResourceUpdateControllerTest
, ZeroUploads
) {
234 AppendFullUploadsToUpdateQueue(0);
235 AppendPartialUploadsToUpdateQueue(0);
238 EXPECT_EQ(0, num_total_flushes_
);
239 EXPECT_EQ(0, num_total_uploads_
);
243 TEST_F(ResourceUpdateControllerTest
, OneFullUpload
) {
244 AppendFullUploadsToUpdateQueue(1);
245 AppendPartialUploadsToUpdateQueue(0);
248 EXPECT_EQ(1, num_total_flushes_
);
249 EXPECT_EQ(1, num_total_uploads_
);
250 EXPECT_EQ(0, num_dangling_uploads_
)
251 << "Last upload wasn't followed by a flush.";
254 TEST_F(ResourceUpdateControllerTest
, OnePartialUpload
) {
255 AppendFullUploadsToUpdateQueue(0);
256 AppendPartialUploadsToUpdateQueue(1);
259 EXPECT_EQ(1, num_total_flushes_
);
260 EXPECT_EQ(1, num_total_uploads_
);
261 EXPECT_EQ(0, num_dangling_uploads_
)
262 << "Last upload wasn't followed by a flush.";
265 TEST_F(ResourceUpdateControllerTest
, OneFullOnePartialUpload
) {
266 AppendFullUploadsToUpdateQueue(1);
267 AppendPartialUploadsToUpdateQueue(1);
270 EXPECT_EQ(1, num_total_flushes_
);
271 EXPECT_EQ(2, num_total_uploads_
);
272 EXPECT_EQ(0, num_dangling_uploads_
)
273 << "Last upload wasn't followed by a flush.";
276 // This class of tests upload a number of textures that is a multiple
277 // of the flush period.
278 const int full_upload_flush_multipler
= 7;
279 const int full_count
= full_upload_flush_multipler
* kFlushPeriodFull
;
281 const int partial_upload_flush_multipler
= 11;
282 const int partial_count
=
283 partial_upload_flush_multipler
* kFlushPeriodPartial
;
285 TEST_F(ResourceUpdateControllerTest
, ManyFullUploads
) {
286 AppendFullUploadsToUpdateQueue(full_count
);
287 AppendPartialUploadsToUpdateQueue(0);
290 EXPECT_EQ(full_upload_flush_multipler
, num_total_flushes_
);
291 EXPECT_EQ(full_count
, num_total_uploads_
);
292 EXPECT_EQ(0, num_dangling_uploads_
)
293 << "Last upload wasn't followed by a flush.";
296 TEST_F(ResourceUpdateControllerTest
, ManyPartialUploads
) {
297 AppendFullUploadsToUpdateQueue(0);
298 AppendPartialUploadsToUpdateQueue(partial_count
);
301 EXPECT_EQ(partial_upload_flush_multipler
, num_total_flushes_
);
302 EXPECT_EQ(partial_count
, num_total_uploads_
);
303 EXPECT_EQ(0, num_dangling_uploads_
)
304 << "Last upload wasn't followed by a flush.";
307 TEST_F(ResourceUpdateControllerTest
, ManyFullManyPartialUploads
) {
308 AppendFullUploadsToUpdateQueue(full_count
);
309 AppendPartialUploadsToUpdateQueue(partial_count
);
312 EXPECT_EQ(full_upload_flush_multipler
+ partial_upload_flush_multipler
,
314 EXPECT_EQ(full_count
+ partial_count
, num_total_uploads_
);
315 EXPECT_EQ(0, num_dangling_uploads_
)
316 << "Last upload wasn't followed by a flush.";
319 class FakeResourceUpdateControllerClient
320 : public ResourceUpdateControllerClient
{
322 FakeResourceUpdateControllerClient() { Reset(); }
323 void Reset() { ready_to_finalize_called_
= false; }
324 bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_
; }
326 void ReadyToFinalizeTextureUpdates() override
{
327 ready_to_finalize_called_
= true;
331 bool ready_to_finalize_called_
;
334 class FakeResourceUpdateController
: public ResourceUpdateController
{
336 static scoped_ptr
<FakeResourceUpdateController
> Create(
337 ResourceUpdateControllerClient
* client
,
338 base::TestSimpleTaskRunner
* task_runner
,
339 scoped_ptr
<ResourceUpdateQueue
> queue
,
340 ResourceProvider
* resource_provider
) {
341 return make_scoped_ptr(new FakeResourceUpdateController(
342 client
, task_runner
, queue
.Pass(), resource_provider
));
345 void SetNow(base::TimeTicks time
) { now_
= time
; }
346 base::TimeTicks
Now() const { return now_
; }
347 void SetUpdateTextureTime(base::TimeDelta time
) {
348 update_textures_time_
= time
;
350 base::TimeTicks
UpdateMoreTexturesCompletionTime() override
{
351 size_t total_updates
=
352 resource_provider_
->NumBlockingUploads() + update_more_textures_size_
;
353 return now_
+ total_updates
* update_textures_time_
;
355 void SetUpdateMoreTexturesSize(size_t size
) {
356 update_more_textures_size_
= size
;
358 size_t UpdateMoreTexturesSize() const override
{
359 return update_more_textures_size_
;
363 FakeResourceUpdateController(ResourceUpdateControllerClient
* client
,
364 base::TestSimpleTaskRunner
* task_runner
,
365 scoped_ptr
<ResourceUpdateQueue
> queue
,
366 ResourceProvider
* resource_provider
)
367 : ResourceUpdateController(
368 client
, task_runner
, queue
.Pass(), resource_provider
),
369 resource_provider_(resource_provider
),
370 update_more_textures_size_(0) {}
372 ResourceProvider
* resource_provider_
;
373 base::TimeTicks now_
;
374 base::TimeDelta update_textures_time_
;
375 size_t update_more_textures_size_
;
378 static void RunPendingTask(base::TestSimpleTaskRunner
* task_runner
,
379 FakeResourceUpdateController
* controller
) {
380 EXPECT_TRUE(task_runner
->HasPendingTask());
381 controller
->SetNow(controller
->Now() + task_runner
->NextPendingTaskDelay());
382 task_runner
->RunPendingTasks();
385 TEST_F(ResourceUpdateControllerTest
, UpdateMoreTextures
) {
386 FakeResourceUpdateControllerClient client
;
387 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
388 new base::TestSimpleTaskRunner
;
390 SetMaxUploadCountPerUpdate(1);
391 AppendFullUploadsToUpdateQueue(3);
392 AppendPartialUploadsToUpdateQueue(0);
394 DebugScopedSetImplThreadAndMainThreadBlocked
395 impl_thread_and_main_thread_blocked(&proxy_
);
396 scoped_ptr
<FakeResourceUpdateController
> controller(
397 FakeResourceUpdateController::Create(&client
,
400 resource_provider_
.get()));
402 controller
->SetNow(controller
->Now() + base::TimeDelta::FromMilliseconds(1));
403 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
404 controller
->SetUpdateMoreTexturesSize(1);
405 // Not enough time for any updates.
406 controller
->PerformMoreUpdates(controller
->Now() +
407 base::TimeDelta::FromMilliseconds(90));
408 EXPECT_FALSE(task_runner
->HasPendingTask());
410 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
411 controller
->SetUpdateMoreTexturesSize(1);
412 // Only enough time for 1 update.
413 controller
->PerformMoreUpdates(controller
->Now() +
414 base::TimeDelta::FromMilliseconds(120));
415 EXPECT_FALSE(task_runner
->HasPendingTask());
416 EXPECT_EQ(1, num_total_uploads_
);
418 // Complete one upload.
419 MakeQueryResultAvailable();
421 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
422 controller
->SetUpdateMoreTexturesSize(1);
423 // Enough time for 2 updates.
424 controller
->PerformMoreUpdates(controller
->Now() +
425 base::TimeDelta::FromMilliseconds(220));
426 RunPendingTask(task_runner
.get(), controller
.get());
427 EXPECT_FALSE(task_runner
->HasPendingTask());
428 EXPECT_TRUE(client
.ReadyToFinalizeCalled());
429 EXPECT_EQ(3, num_total_uploads_
);
432 TEST_F(ResourceUpdateControllerTest
, NoMoreUpdates
) {
433 FakeResourceUpdateControllerClient client
;
434 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
435 new base::TestSimpleTaskRunner
;
437 SetMaxUploadCountPerUpdate(1);
438 AppendFullUploadsToUpdateQueue(2);
439 AppendPartialUploadsToUpdateQueue(0);
441 DebugScopedSetImplThreadAndMainThreadBlocked
442 impl_thread_and_main_thread_blocked(&proxy_
);
443 scoped_ptr
<FakeResourceUpdateController
> controller(
444 FakeResourceUpdateController::Create(&client
,
447 resource_provider_
.get()));
449 controller
->SetNow(controller
->Now() + base::TimeDelta::FromMilliseconds(1));
450 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
451 controller
->SetUpdateMoreTexturesSize(1);
452 // Enough time for 3 updates but only 2 necessary.
453 controller
->PerformMoreUpdates(controller
->Now() +
454 base::TimeDelta::FromMilliseconds(310));
455 RunPendingTask(task_runner
.get(), controller
.get());
456 EXPECT_FALSE(task_runner
->HasPendingTask());
457 EXPECT_TRUE(client
.ReadyToFinalizeCalled());
458 EXPECT_EQ(2, num_total_uploads_
);
461 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
462 controller
->SetUpdateMoreTexturesSize(1);
463 // Enough time for updates but no more updates left.
464 controller
->PerformMoreUpdates(controller
->Now() +
465 base::TimeDelta::FromMilliseconds(310));
467 // ReadyToFinalizeTextureUpdates should only be called once.
468 EXPECT_FALSE(task_runner
->HasPendingTask());
469 EXPECT_FALSE(client
.ReadyToFinalizeCalled());
470 EXPECT_EQ(2, num_total_uploads_
);
473 TEST_F(ResourceUpdateControllerTest
, UpdatesCompleteInFiniteTime
) {
474 FakeResourceUpdateControllerClient client
;
475 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
476 new base::TestSimpleTaskRunner
;
478 SetMaxUploadCountPerUpdate(1);
479 AppendFullUploadsToUpdateQueue(2);
480 AppendPartialUploadsToUpdateQueue(0);
482 DebugScopedSetImplThreadAndMainThreadBlocked
483 impl_thread_and_main_thread_blocked(&proxy_
);
484 scoped_ptr
<FakeResourceUpdateController
> controller(
485 FakeResourceUpdateController::Create(&client
,
488 resource_provider_
.get()));
490 controller
->SetNow(controller
->Now() + base::TimeDelta::FromMilliseconds(1));
491 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500));
492 controller
->SetUpdateMoreTexturesSize(1);
494 for (int i
= 0; i
< 100; i
++) {
495 if (client
.ReadyToFinalizeCalled())
498 // Not enough time for any updates.
499 controller
->PerformMoreUpdates(controller
->Now() +
500 base::TimeDelta::FromMilliseconds(400));
502 if (task_runner
->HasPendingTask())
503 RunPendingTask(task_runner
.get(), controller
.get());
506 EXPECT_FALSE(task_runner
->HasPendingTask());
507 EXPECT_TRUE(client
.ReadyToFinalizeCalled());
508 EXPECT_EQ(2, num_total_uploads_
);