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_web_graphics_context_3d.h"
14 #include "cc/test/tiled_layer_test_common.h"
15 #include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/khronos/GLES2/gl2ext.h"
24 const int kFlushPeriodFull = 4;
25 const int kFlushPeriodPartial = kFlushPeriodFull;
27 class ResourceUpdateControllerTest;
29 class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D {
31 explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test)
34 virtual void flush() OVERRIDE;
35 virtual void shallowFlushCHROMIUM() OVERRIDE;
36 virtual void texSubImage2D(GLenum target,
44 const void* pixels) OVERRIDE;
46 virtual void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value)
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 virtual ~ResourceUpdateControllerTest() {
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 virtual void SetUp() {
110 bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 300, 150);
111 bitmap_.allocPixels();
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_));
128 ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
131 void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count,
133 full_upload_count_expected_ += count;
134 total_upload_count_expected_ += count;
136 const gfx::Rect rect(0, 0, 300, 150);
137 const ResourceUpdate upload = ResourceUpdate::Create(
138 textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
139 for (int i = 0; i < count; i++)
140 queue_->AppendFullUpload(upload);
143 void AppendFullUploadsToUpdateQueue(int count) {
144 AppendFullUploadsOfIndexedTextureToUpdateQueue(count, 0);
147 void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count,
149 partial_count_expected_ += count;
150 total_upload_count_expected_ += count;
152 const gfx::Rect rect(0, 0, 100, 100);
153 const ResourceUpdate upload = ResourceUpdate::Create(
154 textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
155 for (int i = 0; i < count; i++)
156 queue_->AppendPartialUpload(upload);
159 void AppendPartialUploadsToUpdateQueue(int count) {
160 AppendPartialUploadsOfIndexedTextureToUpdateQueue(count, 0);
163 void SetMaxUploadCountPerUpdate(int count) {
164 max_upload_count_per_update_ = count;
167 void UpdateTextures() {
168 DebugScopedSetImplThreadAndMainThreadBlocked
169 impl_thread_and_main_thread_blocked(&proxy_);
170 scoped_ptr<ResourceUpdateController> update_controller =
171 ResourceUpdateController::Create(NULL,
172 proxy_.ImplThreadTaskRunner(),
174 resource_provider_.get());
175 update_controller->Finalize();
178 void MakeQueryResultAvailable() { query_results_available_++; }
181 // Classes required to interact and test the ResourceUpdateController
183 FakeOutputSurfaceClient output_surface_client_;
184 scoped_ptr<OutputSurface> output_surface_;
185 scoped_ptr<ResourceProvider> resource_provider_;
186 scoped_ptr<ResourceUpdateQueue> queue_;
187 scoped_ptr<PrioritizedResource> textures_[4];
188 scoped_ptr<PrioritizedResourceManager> resource_manager_;
190 int query_results_available_;
192 // Properties / expectations of this test
193 int full_upload_count_expected_;
194 int partial_count_expected_;
195 int total_upload_count_expected_;
196 int max_upload_count_per_update_;
198 // Dynamic properties of this test
199 int num_consecutive_flushes_;
200 int num_dangling_uploads_;
201 int num_total_uploads_;
202 int num_total_flushes_;
205 void WebGraphicsContext3DForUploadTest::flush() { test_->OnFlush(); }
207 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() {
211 void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target,
219 const void* pixels) {
223 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id,
226 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
227 *params = test_->IsQueryResultAvailable();
230 // ZERO UPLOADS TESTS
231 TEST_F(ResourceUpdateControllerTest, ZeroUploads) {
232 AppendFullUploadsToUpdateQueue(0);
233 AppendPartialUploadsToUpdateQueue(0);
236 EXPECT_EQ(0, num_total_flushes_);
237 EXPECT_EQ(0, num_total_uploads_);
241 TEST_F(ResourceUpdateControllerTest, OneFullUpload) {
242 AppendFullUploadsToUpdateQueue(1);
243 AppendPartialUploadsToUpdateQueue(0);
246 EXPECT_EQ(1, num_total_flushes_);
247 EXPECT_EQ(1, num_total_uploads_);
248 EXPECT_EQ(0, num_dangling_uploads_)
249 << "Last upload wasn't followed by a flush.";
252 TEST_F(ResourceUpdateControllerTest, OnePartialUpload) {
253 AppendFullUploadsToUpdateQueue(0);
254 AppendPartialUploadsToUpdateQueue(1);
257 EXPECT_EQ(1, num_total_flushes_);
258 EXPECT_EQ(1, num_total_uploads_);
259 EXPECT_EQ(0, num_dangling_uploads_)
260 << "Last upload wasn't followed by a flush.";
263 TEST_F(ResourceUpdateControllerTest, OneFullOnePartialUpload) {
264 AppendFullUploadsToUpdateQueue(1);
265 AppendPartialUploadsToUpdateQueue(1);
268 EXPECT_EQ(1, num_total_flushes_);
269 EXPECT_EQ(2, num_total_uploads_);
270 EXPECT_EQ(0, num_dangling_uploads_)
271 << "Last upload wasn't followed by a flush.";
274 // This class of tests upload a number of textures that is a multiple
275 // of the flush period.
276 const int full_upload_flush_multipler = 7;
277 const int full_count = full_upload_flush_multipler * kFlushPeriodFull;
279 const int partial_upload_flush_multipler = 11;
280 const int partial_count =
281 partial_upload_flush_multipler * kFlushPeriodPartial;
283 TEST_F(ResourceUpdateControllerTest, ManyFullUploads) {
284 AppendFullUploadsToUpdateQueue(full_count);
285 AppendPartialUploadsToUpdateQueue(0);
288 EXPECT_EQ(full_upload_flush_multipler, num_total_flushes_);
289 EXPECT_EQ(full_count, num_total_uploads_);
290 EXPECT_EQ(0, num_dangling_uploads_)
291 << "Last upload wasn't followed by a flush.";
294 TEST_F(ResourceUpdateControllerTest, ManyPartialUploads) {
295 AppendFullUploadsToUpdateQueue(0);
296 AppendPartialUploadsToUpdateQueue(partial_count);
299 EXPECT_EQ(partial_upload_flush_multipler, num_total_flushes_);
300 EXPECT_EQ(partial_count, num_total_uploads_);
301 EXPECT_EQ(0, num_dangling_uploads_)
302 << "Last upload wasn't followed by a flush.";
305 TEST_F(ResourceUpdateControllerTest, ManyFullManyPartialUploads) {
306 AppendFullUploadsToUpdateQueue(full_count);
307 AppendPartialUploadsToUpdateQueue(partial_count);
310 EXPECT_EQ(full_upload_flush_multipler + partial_upload_flush_multipler,
312 EXPECT_EQ(full_count + partial_count, num_total_uploads_);
313 EXPECT_EQ(0, num_dangling_uploads_)
314 << "Last upload wasn't followed by a flush.";
317 class FakeResourceUpdateControllerClient
318 : public ResourceUpdateControllerClient {
320 FakeResourceUpdateControllerClient() { Reset(); }
321 void Reset() { ready_to_finalize_called_ = false; }
322 bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_; }
324 virtual void ReadyToFinalizeTextureUpdates() OVERRIDE {
325 ready_to_finalize_called_ = true;
329 bool ready_to_finalize_called_;
332 class FakeResourceUpdateController : public ResourceUpdateController {
334 static scoped_ptr<FakeResourceUpdateController> Create(
335 ResourceUpdateControllerClient* client,
336 base::TestSimpleTaskRunner* task_runner,
337 scoped_ptr<ResourceUpdateQueue> queue,
338 ResourceProvider* resource_provider) {
339 return make_scoped_ptr(new FakeResourceUpdateController(
340 client, task_runner, queue.Pass(), resource_provider));
343 void SetNow(base::TimeTicks time) { now_ = time; }
344 base::TimeTicks Now() const { return now_; }
345 void SetUpdateTextureTime(base::TimeDelta time) {
346 update_textures_time_ = time;
348 virtual base::TimeTicks UpdateMoreTexturesCompletionTime() OVERRIDE {
349 size_t total_updates =
350 resource_provider_->NumBlockingUploads() + update_more_textures_size_;
351 return now_ + total_updates * update_textures_time_;
353 void SetUpdateMoreTexturesSize(size_t size) {
354 update_more_textures_size_ = size;
356 virtual size_t UpdateMoreTexturesSize() const OVERRIDE {
357 return update_more_textures_size_;
361 FakeResourceUpdateController(ResourceUpdateControllerClient* client,
362 base::TestSimpleTaskRunner* task_runner,
363 scoped_ptr<ResourceUpdateQueue> queue,
364 ResourceProvider* resource_provider)
365 : ResourceUpdateController(
366 client, task_runner, queue.Pass(), resource_provider),
367 resource_provider_(resource_provider),
368 update_more_textures_size_(0) {}
370 ResourceProvider* resource_provider_;
371 base::TimeTicks now_;
372 base::TimeDelta update_textures_time_;
373 size_t update_more_textures_size_;
376 static void RunPendingTask(base::TestSimpleTaskRunner* task_runner,
377 FakeResourceUpdateController* controller) {
378 EXPECT_TRUE(task_runner->HasPendingTask());
379 controller->SetNow(controller->Now() + task_runner->NextPendingTaskDelay());
380 task_runner->RunPendingTasks();
383 TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) {
384 FakeResourceUpdateControllerClient client;
385 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
386 new base::TestSimpleTaskRunner;
388 SetMaxUploadCountPerUpdate(1);
389 AppendFullUploadsToUpdateQueue(3);
390 AppendPartialUploadsToUpdateQueue(0);
392 DebugScopedSetImplThreadAndMainThreadBlocked
393 impl_thread_and_main_thread_blocked(&proxy_);
394 scoped_ptr<FakeResourceUpdateController> controller(
395 FakeResourceUpdateController::Create(&client,
398 resource_provider_.get()));
400 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
401 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
402 controller->SetUpdateMoreTexturesSize(1);
403 // Not enough time for any updates.
404 controller->PerformMoreUpdates(controller->Now() +
405 base::TimeDelta::FromMilliseconds(90));
406 EXPECT_FALSE(task_runner->HasPendingTask());
408 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
409 controller->SetUpdateMoreTexturesSize(1);
410 // Only enough time for 1 update.
411 controller->PerformMoreUpdates(controller->Now() +
412 base::TimeDelta::FromMilliseconds(120));
413 EXPECT_FALSE(task_runner->HasPendingTask());
414 EXPECT_EQ(1, num_total_uploads_);
416 // Complete one upload.
417 MakeQueryResultAvailable();
419 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
420 controller->SetUpdateMoreTexturesSize(1);
421 // Enough time for 2 updates.
422 controller->PerformMoreUpdates(controller->Now() +
423 base::TimeDelta::FromMilliseconds(220));
424 RunPendingTask(task_runner.get(), controller.get());
425 EXPECT_FALSE(task_runner->HasPendingTask());
426 EXPECT_TRUE(client.ReadyToFinalizeCalled());
427 EXPECT_EQ(3, num_total_uploads_);
430 TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) {
431 FakeResourceUpdateControllerClient client;
432 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
433 new base::TestSimpleTaskRunner;
435 SetMaxUploadCountPerUpdate(1);
436 AppendFullUploadsToUpdateQueue(2);
437 AppendPartialUploadsToUpdateQueue(0);
439 DebugScopedSetImplThreadAndMainThreadBlocked
440 impl_thread_and_main_thread_blocked(&proxy_);
441 scoped_ptr<FakeResourceUpdateController> controller(
442 FakeResourceUpdateController::Create(&client,
445 resource_provider_.get()));
447 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
448 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
449 controller->SetUpdateMoreTexturesSize(1);
450 // Enough time for 3 updates but only 2 necessary.
451 controller->PerformMoreUpdates(controller->Now() +
452 base::TimeDelta::FromMilliseconds(310));
453 RunPendingTask(task_runner.get(), controller.get());
454 EXPECT_FALSE(task_runner->HasPendingTask());
455 EXPECT_TRUE(client.ReadyToFinalizeCalled());
456 EXPECT_EQ(2, num_total_uploads_);
458 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
459 controller->SetUpdateMoreTexturesSize(1);
460 // Enough time for updates but no more updates left.
461 controller->PerformMoreUpdates(controller->Now() +
462 base::TimeDelta::FromMilliseconds(310));
463 // 0-delay task used to call ReadyToFinalizeTextureUpdates().
464 RunPendingTask(task_runner.get(), controller.get());
465 EXPECT_FALSE(task_runner->HasPendingTask());
466 EXPECT_TRUE(client.ReadyToFinalizeCalled());
467 EXPECT_EQ(2, num_total_uploads_);
470 TEST_F(ResourceUpdateControllerTest, UpdatesCompleteInFiniteTime) {
471 FakeResourceUpdateControllerClient client;
472 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
473 new base::TestSimpleTaskRunner;
475 SetMaxUploadCountPerUpdate(1);
476 AppendFullUploadsToUpdateQueue(2);
477 AppendPartialUploadsToUpdateQueue(0);
479 DebugScopedSetImplThreadAndMainThreadBlocked
480 impl_thread_and_main_thread_blocked(&proxy_);
481 scoped_ptr<FakeResourceUpdateController> controller(
482 FakeResourceUpdateController::Create(&client,
485 resource_provider_.get()));
487 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
488 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500));
489 controller->SetUpdateMoreTexturesSize(1);
491 for (int i = 0; i < 100; i++) {
492 if (client.ReadyToFinalizeCalled())
495 // Not enough time for any updates.
496 controller->PerformMoreUpdates(controller->Now() +
497 base::TimeDelta::FromMilliseconds(400));
499 if (task_runner->HasPendingTask())
500 RunPendingTask(task_runner.get(), controller.get());
503 EXPECT_FALSE(task_runner->HasPendingTask());
504 EXPECT_TRUE(client.ReadyToFinalizeCalled());
505 EXPECT_EQ(2, num_total_uploads_);