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 virtual void flush() OVERRIDE
;
36 virtual void shallowFlushCHROMIUM() OVERRIDE
;
37 virtual void texSubImage2D(GLenum target
,
45 const void* pixels
) OVERRIDE
;
47 virtual void getQueryObjectuivEXT(GLuint id
, GLenum pname
, GLuint
* value
)
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 virtual ~ResourceUpdateControllerTest() {
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 virtual void SetUp() {
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_
= ResourceProvider::Create(
129 output_surface_
.get(), shared_bitmap_manager_
.get(), 0, false, 1,
133 void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count
,
135 full_upload_count_expected_
+= count
;
136 total_upload_count_expected_
+= count
;
138 const gfx::Rect
rect(0, 0, 300, 150);
139 const ResourceUpdate upload
= ResourceUpdate::Create(
140 textures_
[texture_index
].get(), &bitmap_
, rect
, rect
, gfx::Vector2d());
141 for (int i
= 0; i
< count
; i
++)
142 queue_
->AppendFullUpload(upload
);
145 void AppendFullUploadsToUpdateQueue(int count
) {
146 AppendFullUploadsOfIndexedTextureToUpdateQueue(count
, 0);
149 void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count
,
151 partial_count_expected_
+= count
;
152 total_upload_count_expected_
+= count
;
154 const gfx::Rect
rect(0, 0, 100, 100);
155 const ResourceUpdate upload
= ResourceUpdate::Create(
156 textures_
[texture_index
].get(), &bitmap_
, rect
, rect
, gfx::Vector2d());
157 for (int i
= 0; i
< count
; i
++)
158 queue_
->AppendPartialUpload(upload
);
161 void AppendPartialUploadsToUpdateQueue(int count
) {
162 AppendPartialUploadsOfIndexedTextureToUpdateQueue(count
, 0);
165 void SetMaxUploadCountPerUpdate(int count
) {
166 max_upload_count_per_update_
= count
;
169 void UpdateTextures() {
170 DebugScopedSetImplThreadAndMainThreadBlocked
171 impl_thread_and_main_thread_blocked(&proxy_
);
172 scoped_ptr
<ResourceUpdateController
> update_controller
=
173 ResourceUpdateController::Create(NULL
,
174 proxy_
.ImplThreadTaskRunner(),
176 resource_provider_
.get());
177 update_controller
->Finalize();
180 void MakeQueryResultAvailable() { query_results_available_
++; }
183 // Classes required to interact and test the ResourceUpdateController
185 FakeOutputSurfaceClient output_surface_client_
;
186 scoped_ptr
<OutputSurface
> output_surface_
;
187 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
188 scoped_ptr
<ResourceProvider
> resource_provider_
;
189 scoped_ptr
<ResourceUpdateQueue
> queue_
;
190 scoped_ptr
<PrioritizedResource
> textures_
[4];
191 scoped_ptr
<PrioritizedResourceManager
> resource_manager_
;
193 int query_results_available_
;
195 // Properties / expectations of this test
196 int full_upload_count_expected_
;
197 int partial_count_expected_
;
198 int total_upload_count_expected_
;
199 int max_upload_count_per_update_
;
201 // Dynamic properties of this test
202 int num_consecutive_flushes_
;
203 int num_dangling_uploads_
;
204 int num_total_uploads_
;
205 int num_total_flushes_
;
208 void WebGraphicsContext3DForUploadTest::flush() { test_
->OnFlush(); }
210 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() {
214 void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target
,
222 const void* pixels
) {
226 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id
,
229 if (pname
== GL_QUERY_RESULT_AVAILABLE_EXT
)
230 *params
= test_
->IsQueryResultAvailable();
233 // ZERO UPLOADS TESTS
234 TEST_F(ResourceUpdateControllerTest
, ZeroUploads
) {
235 AppendFullUploadsToUpdateQueue(0);
236 AppendPartialUploadsToUpdateQueue(0);
239 EXPECT_EQ(0, num_total_flushes_
);
240 EXPECT_EQ(0, num_total_uploads_
);
244 TEST_F(ResourceUpdateControllerTest
, OneFullUpload
) {
245 AppendFullUploadsToUpdateQueue(1);
246 AppendPartialUploadsToUpdateQueue(0);
249 EXPECT_EQ(1, num_total_flushes_
);
250 EXPECT_EQ(1, num_total_uploads_
);
251 EXPECT_EQ(0, num_dangling_uploads_
)
252 << "Last upload wasn't followed by a flush.";
255 TEST_F(ResourceUpdateControllerTest
, OnePartialUpload
) {
256 AppendFullUploadsToUpdateQueue(0);
257 AppendPartialUploadsToUpdateQueue(1);
260 EXPECT_EQ(1, num_total_flushes_
);
261 EXPECT_EQ(1, num_total_uploads_
);
262 EXPECT_EQ(0, num_dangling_uploads_
)
263 << "Last upload wasn't followed by a flush.";
266 TEST_F(ResourceUpdateControllerTest
, OneFullOnePartialUpload
) {
267 AppendFullUploadsToUpdateQueue(1);
268 AppendPartialUploadsToUpdateQueue(1);
271 EXPECT_EQ(1, num_total_flushes_
);
272 EXPECT_EQ(2, num_total_uploads_
);
273 EXPECT_EQ(0, num_dangling_uploads_
)
274 << "Last upload wasn't followed by a flush.";
277 // This class of tests upload a number of textures that is a multiple
278 // of the flush period.
279 const int full_upload_flush_multipler
= 7;
280 const int full_count
= full_upload_flush_multipler
* kFlushPeriodFull
;
282 const int partial_upload_flush_multipler
= 11;
283 const int partial_count
=
284 partial_upload_flush_multipler
* kFlushPeriodPartial
;
286 TEST_F(ResourceUpdateControllerTest
, ManyFullUploads
) {
287 AppendFullUploadsToUpdateQueue(full_count
);
288 AppendPartialUploadsToUpdateQueue(0);
291 EXPECT_EQ(full_upload_flush_multipler
, num_total_flushes_
);
292 EXPECT_EQ(full_count
, num_total_uploads_
);
293 EXPECT_EQ(0, num_dangling_uploads_
)
294 << "Last upload wasn't followed by a flush.";
297 TEST_F(ResourceUpdateControllerTest
, ManyPartialUploads
) {
298 AppendFullUploadsToUpdateQueue(0);
299 AppendPartialUploadsToUpdateQueue(partial_count
);
302 EXPECT_EQ(partial_upload_flush_multipler
, num_total_flushes_
);
303 EXPECT_EQ(partial_count
, num_total_uploads_
);
304 EXPECT_EQ(0, num_dangling_uploads_
)
305 << "Last upload wasn't followed by a flush.";
308 TEST_F(ResourceUpdateControllerTest
, ManyFullManyPartialUploads
) {
309 AppendFullUploadsToUpdateQueue(full_count
);
310 AppendPartialUploadsToUpdateQueue(partial_count
);
313 EXPECT_EQ(full_upload_flush_multipler
+ partial_upload_flush_multipler
,
315 EXPECT_EQ(full_count
+ partial_count
, num_total_uploads_
);
316 EXPECT_EQ(0, num_dangling_uploads_
)
317 << "Last upload wasn't followed by a flush.";
320 class FakeResourceUpdateControllerClient
321 : public ResourceUpdateControllerClient
{
323 FakeResourceUpdateControllerClient() { Reset(); }
324 void Reset() { ready_to_finalize_called_
= false; }
325 bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_
; }
327 virtual void ReadyToFinalizeTextureUpdates() OVERRIDE
{
328 ready_to_finalize_called_
= true;
332 bool ready_to_finalize_called_
;
335 class FakeResourceUpdateController
: public ResourceUpdateController
{
337 static scoped_ptr
<FakeResourceUpdateController
> Create(
338 ResourceUpdateControllerClient
* client
,
339 base::TestSimpleTaskRunner
* task_runner
,
340 scoped_ptr
<ResourceUpdateQueue
> queue
,
341 ResourceProvider
* resource_provider
) {
342 return make_scoped_ptr(new FakeResourceUpdateController(
343 client
, task_runner
, queue
.Pass(), resource_provider
));
346 void SetNow(base::TimeTicks time
) { now_
= time
; }
347 base::TimeTicks
Now() const { return now_
; }
348 void SetUpdateTextureTime(base::TimeDelta time
) {
349 update_textures_time_
= time
;
351 virtual base::TimeTicks
UpdateMoreTexturesCompletionTime() OVERRIDE
{
352 size_t total_updates
=
353 resource_provider_
->NumBlockingUploads() + update_more_textures_size_
;
354 return now_
+ total_updates
* update_textures_time_
;
356 void SetUpdateMoreTexturesSize(size_t size
) {
357 update_more_textures_size_
= size
;
359 virtual size_t UpdateMoreTexturesSize() const OVERRIDE
{
360 return update_more_textures_size_
;
364 FakeResourceUpdateController(ResourceUpdateControllerClient
* client
,
365 base::TestSimpleTaskRunner
* task_runner
,
366 scoped_ptr
<ResourceUpdateQueue
> queue
,
367 ResourceProvider
* resource_provider
)
368 : ResourceUpdateController(
369 client
, task_runner
, queue
.Pass(), resource_provider
),
370 resource_provider_(resource_provider
),
371 update_more_textures_size_(0) {}
373 ResourceProvider
* resource_provider_
;
374 base::TimeTicks now_
;
375 base::TimeDelta update_textures_time_
;
376 size_t update_more_textures_size_
;
379 static void RunPendingTask(base::TestSimpleTaskRunner
* task_runner
,
380 FakeResourceUpdateController
* controller
) {
381 EXPECT_TRUE(task_runner
->HasPendingTask());
382 controller
->SetNow(controller
->Now() + task_runner
->NextPendingTaskDelay());
383 task_runner
->RunPendingTasks();
386 TEST_F(ResourceUpdateControllerTest
, UpdateMoreTextures
) {
387 FakeResourceUpdateControllerClient client
;
388 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
389 new base::TestSimpleTaskRunner
;
391 SetMaxUploadCountPerUpdate(1);
392 AppendFullUploadsToUpdateQueue(3);
393 AppendPartialUploadsToUpdateQueue(0);
395 DebugScopedSetImplThreadAndMainThreadBlocked
396 impl_thread_and_main_thread_blocked(&proxy_
);
397 scoped_ptr
<FakeResourceUpdateController
> controller(
398 FakeResourceUpdateController::Create(&client
,
401 resource_provider_
.get()));
403 controller
->SetNow(controller
->Now() + base::TimeDelta::FromMilliseconds(1));
404 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
405 controller
->SetUpdateMoreTexturesSize(1);
406 // Not enough time for any updates.
407 controller
->PerformMoreUpdates(controller
->Now() +
408 base::TimeDelta::FromMilliseconds(90));
409 EXPECT_FALSE(task_runner
->HasPendingTask());
411 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
412 controller
->SetUpdateMoreTexturesSize(1);
413 // Only enough time for 1 update.
414 controller
->PerformMoreUpdates(controller
->Now() +
415 base::TimeDelta::FromMilliseconds(120));
416 EXPECT_FALSE(task_runner
->HasPendingTask());
417 EXPECT_EQ(1, num_total_uploads_
);
419 // Complete one upload.
420 MakeQueryResultAvailable();
422 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
423 controller
->SetUpdateMoreTexturesSize(1);
424 // Enough time for 2 updates.
425 controller
->PerformMoreUpdates(controller
->Now() +
426 base::TimeDelta::FromMilliseconds(220));
427 RunPendingTask(task_runner
.get(), controller
.get());
428 EXPECT_FALSE(task_runner
->HasPendingTask());
429 EXPECT_TRUE(client
.ReadyToFinalizeCalled());
430 EXPECT_EQ(3, num_total_uploads_
);
433 TEST_F(ResourceUpdateControllerTest
, NoMoreUpdates
) {
434 FakeResourceUpdateControllerClient client
;
435 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
436 new base::TestSimpleTaskRunner
;
438 SetMaxUploadCountPerUpdate(1);
439 AppendFullUploadsToUpdateQueue(2);
440 AppendPartialUploadsToUpdateQueue(0);
442 DebugScopedSetImplThreadAndMainThreadBlocked
443 impl_thread_and_main_thread_blocked(&proxy_
);
444 scoped_ptr
<FakeResourceUpdateController
> controller(
445 FakeResourceUpdateController::Create(&client
,
448 resource_provider_
.get()));
450 controller
->SetNow(controller
->Now() + base::TimeDelta::FromMilliseconds(1));
451 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
452 controller
->SetUpdateMoreTexturesSize(1);
453 // Enough time for 3 updates but only 2 necessary.
454 controller
->PerformMoreUpdates(controller
->Now() +
455 base::TimeDelta::FromMilliseconds(310));
456 RunPendingTask(task_runner
.get(), controller
.get());
457 EXPECT_FALSE(task_runner
->HasPendingTask());
458 EXPECT_TRUE(client
.ReadyToFinalizeCalled());
459 EXPECT_EQ(2, num_total_uploads_
);
462 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
463 controller
->SetUpdateMoreTexturesSize(1);
464 // Enough time for updates but no more updates left.
465 controller
->PerformMoreUpdates(controller
->Now() +
466 base::TimeDelta::FromMilliseconds(310));
468 // ReadyToFinalizeTextureUpdates should only be called once.
469 EXPECT_FALSE(task_runner
->HasPendingTask());
470 EXPECT_FALSE(client
.ReadyToFinalizeCalled());
471 EXPECT_EQ(2, num_total_uploads_
);
474 TEST_F(ResourceUpdateControllerTest
, UpdatesCompleteInFiniteTime
) {
475 FakeResourceUpdateControllerClient client
;
476 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
477 new base::TestSimpleTaskRunner
;
479 SetMaxUploadCountPerUpdate(1);
480 AppendFullUploadsToUpdateQueue(2);
481 AppendPartialUploadsToUpdateQueue(0);
483 DebugScopedSetImplThreadAndMainThreadBlocked
484 impl_thread_and_main_thread_blocked(&proxy_
);
485 scoped_ptr
<FakeResourceUpdateController
> controller(
486 FakeResourceUpdateController::Create(&client
,
489 resource_provider_
.get()));
491 controller
->SetNow(controller
->Now() + base::TimeDelta::FromMilliseconds(1));
492 controller
->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500));
493 controller
->SetUpdateMoreTexturesSize(1);
495 for (int i
= 0; i
< 100; i
++) {
496 if (client
.ReadyToFinalizeCalled())
499 // Not enough time for any updates.
500 controller
->PerformMoreUpdates(controller
->Now() +
501 base::TimeDelta::FromMilliseconds(400));
503 if (task_runner
->HasPendingTask())
504 RunPendingTask(task_runner
.get(), controller
.get());
507 EXPECT_FALSE(task_runner
->HasPendingTask());
508 EXPECT_TRUE(client
.ReadyToFinalizeCalled());
509 EXPECT_EQ(2, num_total_uploads_
);