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"
20 using WebKit::WGC3Denum;
21 using WebKit::WGC3Dint;
22 using WebKit::WGC3Duint;
23 using WebKit::WGC3Dsizei;
24 using WebKit::WebGLId;
25 using WebKit::WebString;
30 const int kFlushPeriodFull = 4;
31 const int kFlushPeriodPartial = kFlushPeriodFull;
33 class ResourceUpdateControllerTest;
35 class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D {
37 explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test)
39 test_capabilities_.shallow_flush = true;
42 virtual void flush() OVERRIDE;
43 virtual void shallowFlushCHROMIUM() OVERRIDE;
44 virtual void texSubImage2D(
53 const void* pixels) OVERRIDE;
54 virtual GrGLInterface* createGrGLInterface() OVERRIDE { return NULL; }
56 virtual void getQueryObjectuivEXT(
62 ResourceUpdateControllerTest* test_;
65 class ResourceUpdateControllerTest : public Test {
67 ResourceUpdateControllerTest()
69 queue_(make_scoped_ptr(new ResourceUpdateQueue)),
70 resource_manager_(PrioritizedResourceManager::Create(&proxy_)),
71 query_results_available_(0),
72 full_upload_count_expected_(0),
73 partial_count_expected_(0),
74 total_upload_count_expected_(0),
75 max_upload_count_per_update_(0),
76 num_consecutive_flushes_(0),
77 num_dangling_uploads_(0),
78 num_total_uploads_(0),
79 num_total_flushes_(0) {}
81 virtual ~ResourceUpdateControllerTest() {
82 DebugScopedSetImplThreadAndMainThreadBlocked
83 impl_thread_and_main_thread_blocked(&proxy_);
84 resource_manager_->ClearAllMemory(resource_provider_.get());
89 // Check for back-to-back flushes.
90 EXPECT_EQ(0, num_consecutive_flushes_) << "Back-to-back flushes detected.";
92 num_dangling_uploads_ = 0;
93 num_consecutive_flushes_++;
98 // Check for too many consecutive uploads
99 if (num_total_uploads_ < full_upload_count_expected_) {
100 EXPECT_LT(num_dangling_uploads_, kFlushPeriodFull)
101 << "Too many consecutive full uploads detected.";
103 EXPECT_LT(num_dangling_uploads_, kFlushPeriodPartial)
104 << "Too many consecutive partial uploads detected.";
107 num_consecutive_flushes_ = 0;
108 num_dangling_uploads_++;
109 num_total_uploads_++;
112 bool IsQueryResultAvailable() {
113 if (!query_results_available_)
116 query_results_available_--;
121 virtual void SetUp() {
122 bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 300, 150);
123 bitmap_.allocPixels();
125 for (int i = 0; i < 4; i++) {
126 textures_[i] = PrioritizedResource::Create(resource_manager_.get(),
130 set_request_priority(PriorityCalculator::VisiblePriority(true));
132 resource_manager_->PrioritizeTextures();
134 output_surface_ = FakeOutputSurface::Create3d(
135 scoped_ptr<TestWebGraphicsContext3D>(
136 new WebGraphicsContext3DForUploadTest(this)));
137 CHECK(output_surface_->BindToClient(&output_surface_client_));
140 ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
143 void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count,
145 full_upload_count_expected_ += count;
146 total_upload_count_expected_ += count;
148 const gfx::Rect rect(0, 0, 300, 150);
149 const ResourceUpdate upload = ResourceUpdate::Create(
150 textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
151 for (int i = 0; i < count; i++)
152 queue_->AppendFullUpload(upload);
155 void AppendFullUploadsToUpdateQueue(int count) {
156 AppendFullUploadsOfIndexedTextureToUpdateQueue(count, 0);
159 void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count,
161 partial_count_expected_ += count;
162 total_upload_count_expected_ += count;
164 const gfx::Rect rect(0, 0, 100, 100);
165 const ResourceUpdate upload = ResourceUpdate::Create(
166 textures_[texture_index].get(), &bitmap_, rect, rect, gfx::Vector2d());
167 for (int i = 0; i < count; i++)
168 queue_->AppendPartialUpload(upload);
171 void AppendPartialUploadsToUpdateQueue(int count) {
172 AppendPartialUploadsOfIndexedTextureToUpdateQueue(count, 0);
175 void SetMaxUploadCountPerUpdate(int count) {
176 max_upload_count_per_update_ = count;
179 void UpdateTextures() {
180 DebugScopedSetImplThreadAndMainThreadBlocked
181 impl_thread_and_main_thread_blocked(&proxy_);
182 scoped_ptr<ResourceUpdateController> update_controller =
183 ResourceUpdateController::Create(NULL,
184 proxy_.ImplThreadTaskRunner(),
186 resource_provider_.get());
187 update_controller->Finalize();
190 void MakeQueryResultAvailable() { query_results_available_++; }
193 // Classes required to interact and test the ResourceUpdateController
195 FakeOutputSurfaceClient output_surface_client_;
196 scoped_ptr<OutputSurface> output_surface_;
197 scoped_ptr<ResourceProvider> resource_provider_;
198 scoped_ptr<ResourceUpdateQueue> queue_;
199 scoped_ptr<PrioritizedResource> textures_[4];
200 scoped_ptr<PrioritizedResourceManager> resource_manager_;
202 int query_results_available_;
204 // Properties / expectations of this test
205 int full_upload_count_expected_;
206 int partial_count_expected_;
207 int total_upload_count_expected_;
208 int max_upload_count_per_update_;
210 // Dynamic properties of this test
211 int num_consecutive_flushes_;
212 int num_dangling_uploads_;
213 int num_total_uploads_;
214 int num_total_flushes_;
217 void WebGraphicsContext3DForUploadTest::flush() { test_->OnFlush(); }
219 void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() {
223 void WebGraphicsContext3DForUploadTest::texSubImage2D(
232 const void* pixels) {
236 void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(
240 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
241 *params = test_->IsQueryResultAvailable();
244 // ZERO UPLOADS TESTS
245 TEST_F(ResourceUpdateControllerTest, ZeroUploads) {
246 AppendFullUploadsToUpdateQueue(0);
247 AppendPartialUploadsToUpdateQueue(0);
250 EXPECT_EQ(0, num_total_flushes_);
251 EXPECT_EQ(0, num_total_uploads_);
255 TEST_F(ResourceUpdateControllerTest, OneFullUpload) {
256 AppendFullUploadsToUpdateQueue(1);
257 AppendPartialUploadsToUpdateQueue(0);
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, OnePartialUpload) {
267 AppendFullUploadsToUpdateQueue(0);
268 AppendPartialUploadsToUpdateQueue(1);
271 EXPECT_EQ(1, num_total_flushes_);
272 EXPECT_EQ(1, num_total_uploads_);
273 EXPECT_EQ(0, num_dangling_uploads_)
274 << "Last upload wasn't followed by a flush.";
277 TEST_F(ResourceUpdateControllerTest, OneFullOnePartialUpload) {
278 AppendFullUploadsToUpdateQueue(1);
279 AppendPartialUploadsToUpdateQueue(1);
282 EXPECT_EQ(1, num_total_flushes_);
283 EXPECT_EQ(2, num_total_uploads_);
284 EXPECT_EQ(0, num_dangling_uploads_)
285 << "Last upload wasn't followed by a flush.";
288 // This class of tests upload a number of textures that is a multiple
289 // of the flush period.
290 const int full_upload_flush_multipler = 7;
291 const int full_count = full_upload_flush_multipler * kFlushPeriodFull;
293 const int partial_upload_flush_multipler = 11;
294 const int partial_count =
295 partial_upload_flush_multipler * kFlushPeriodPartial;
297 TEST_F(ResourceUpdateControllerTest, ManyFullUploads) {
298 AppendFullUploadsToUpdateQueue(full_count);
299 AppendPartialUploadsToUpdateQueue(0);
302 EXPECT_EQ(full_upload_flush_multipler, num_total_flushes_);
303 EXPECT_EQ(full_count, num_total_uploads_);
304 EXPECT_EQ(0, num_dangling_uploads_)
305 << "Last upload wasn't followed by a flush.";
308 TEST_F(ResourceUpdateControllerTest, ManyPartialUploads) {
309 AppendFullUploadsToUpdateQueue(0);
310 AppendPartialUploadsToUpdateQueue(partial_count);
313 EXPECT_EQ(partial_upload_flush_multipler, num_total_flushes_);
314 EXPECT_EQ(partial_count, num_total_uploads_);
315 EXPECT_EQ(0, num_dangling_uploads_)
316 << "Last upload wasn't followed by a flush.";
319 TEST_F(ResourceUpdateControllerTest, ManyFullManyPartialUploads) {
320 AppendFullUploadsToUpdateQueue(full_count);
321 AppendPartialUploadsToUpdateQueue(partial_count);
324 EXPECT_EQ(full_upload_flush_multipler + partial_upload_flush_multipler,
326 EXPECT_EQ(full_count + partial_count, num_total_uploads_);
327 EXPECT_EQ(0, num_dangling_uploads_)
328 << "Last upload wasn't followed by a flush.";
331 class FakeResourceUpdateControllerClient
332 : public ResourceUpdateControllerClient {
334 FakeResourceUpdateControllerClient() { Reset(); }
335 void Reset() { ready_to_finalize_called_ = false; }
336 bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_; }
338 virtual void ReadyToFinalizeTextureUpdates() OVERRIDE {
339 ready_to_finalize_called_ = true;
343 bool ready_to_finalize_called_;
346 class FakeResourceUpdateController : public ResourceUpdateController {
348 static scoped_ptr<FakeResourceUpdateController> Create(
349 ResourceUpdateControllerClient* client,
350 base::TestSimpleTaskRunner* task_runner,
351 scoped_ptr<ResourceUpdateQueue> queue,
352 ResourceProvider* resource_provider) {
353 return make_scoped_ptr(new FakeResourceUpdateController(
354 client, task_runner, queue.Pass(), resource_provider));
357 void SetNow(base::TimeTicks time) { now_ = time; }
358 virtual base::TimeTicks Now() const OVERRIDE { return now_; }
359 void SetUpdateMoreTexturesTime(base::TimeDelta time) {
360 update_more_textures_time_ = time;
362 virtual base::TimeDelta UpdateMoreTexturesTime() const OVERRIDE {
363 return update_more_textures_time_;
365 void SetUpdateMoreTexturesSize(size_t size) {
366 update_more_textures_size_ = size;
368 virtual size_t UpdateMoreTexturesSize() const OVERRIDE {
369 return update_more_textures_size_;
373 FakeResourceUpdateController(ResourceUpdateControllerClient* client,
374 base::TestSimpleTaskRunner* task_runner,
375 scoped_ptr<ResourceUpdateQueue> queue,
376 ResourceProvider* resource_provider)
377 : ResourceUpdateController(
378 client, task_runner, queue.Pass(), resource_provider),
379 update_more_textures_size_(0) {}
381 base::TimeTicks now_;
382 base::TimeDelta update_more_textures_time_;
383 size_t update_more_textures_size_;
386 static void RunPendingTask(base::TestSimpleTaskRunner* task_runner,
387 FakeResourceUpdateController* controller) {
388 EXPECT_TRUE(task_runner->HasPendingTask());
389 controller->SetNow(controller->Now() + task_runner->NextPendingTaskDelay());
390 task_runner->RunPendingTasks();
393 TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) {
394 FakeResourceUpdateControllerClient client;
395 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
396 new base::TestSimpleTaskRunner;
398 SetMaxUploadCountPerUpdate(1);
399 AppendFullUploadsToUpdateQueue(3);
400 AppendPartialUploadsToUpdateQueue(0);
402 DebugScopedSetImplThreadAndMainThreadBlocked
403 impl_thread_and_main_thread_blocked(&proxy_);
404 scoped_ptr<FakeResourceUpdateController> controller(
405 FakeResourceUpdateController::Create(&client,
408 resource_provider_.get()));
410 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
411 controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100));
412 controller->SetUpdateMoreTexturesSize(1);
413 // Not enough time for any updates.
414 controller->PerformMoreUpdates(controller->Now() +
415 base::TimeDelta::FromMilliseconds(90));
416 EXPECT_FALSE(task_runner->HasPendingTask());
418 controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100));
419 controller->SetUpdateMoreTexturesSize(1);
420 // Only enough time for 1 update.
421 controller->PerformMoreUpdates(controller->Now() +
422 base::TimeDelta::FromMilliseconds(120));
423 EXPECT_FALSE(task_runner->HasPendingTask());
424 EXPECT_EQ(1, num_total_uploads_);
426 // Complete one upload.
427 MakeQueryResultAvailable();
429 controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100));
430 controller->SetUpdateMoreTexturesSize(1);
431 // Enough time for 2 updates.
432 controller->PerformMoreUpdates(controller->Now() +
433 base::TimeDelta::FromMilliseconds(220));
434 RunPendingTask(task_runner.get(), controller.get());
435 EXPECT_FALSE(task_runner->HasPendingTask());
436 EXPECT_TRUE(client.ReadyToFinalizeCalled());
437 EXPECT_EQ(3, num_total_uploads_);
440 TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) {
441 FakeResourceUpdateControllerClient client;
442 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
443 new base::TestSimpleTaskRunner;
445 SetMaxUploadCountPerUpdate(1);
446 AppendFullUploadsToUpdateQueue(2);
447 AppendPartialUploadsToUpdateQueue(0);
449 DebugScopedSetImplThreadAndMainThreadBlocked
450 impl_thread_and_main_thread_blocked(&proxy_);
451 scoped_ptr<FakeResourceUpdateController> controller(
452 FakeResourceUpdateController::Create(&client,
455 resource_provider_.get()));
457 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
458 controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100));
459 controller->SetUpdateMoreTexturesSize(1);
460 // Enough time for 3 updates but only 2 necessary.
461 controller->PerformMoreUpdates(controller->Now() +
462 base::TimeDelta::FromMilliseconds(310));
463 RunPendingTask(task_runner.get(), controller.get());
464 EXPECT_FALSE(task_runner->HasPendingTask());
465 EXPECT_TRUE(client.ReadyToFinalizeCalled());
466 EXPECT_EQ(2, num_total_uploads_);
468 controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(100));
469 controller->SetUpdateMoreTexturesSize(1);
470 // Enough time for updates but no more updates left.
471 controller->PerformMoreUpdates(controller->Now() +
472 base::TimeDelta::FromMilliseconds(310));
473 // 0-delay task used to call ReadyToFinalizeTextureUpdates().
474 RunPendingTask(task_runner.get(), controller.get());
475 EXPECT_FALSE(task_runner->HasPendingTask());
476 EXPECT_TRUE(client.ReadyToFinalizeCalled());
477 EXPECT_EQ(2, num_total_uploads_);
480 TEST_F(ResourceUpdateControllerTest, UpdatesCompleteInFiniteTime) {
481 FakeResourceUpdateControllerClient client;
482 scoped_refptr<base::TestSimpleTaskRunner> task_runner =
483 new base::TestSimpleTaskRunner;
485 SetMaxUploadCountPerUpdate(1);
486 AppendFullUploadsToUpdateQueue(2);
487 AppendPartialUploadsToUpdateQueue(0);
489 DebugScopedSetImplThreadAndMainThreadBlocked
490 impl_thread_and_main_thread_blocked(&proxy_);
491 scoped_ptr<FakeResourceUpdateController> controller(
492 FakeResourceUpdateController::Create(&client,
495 resource_provider_.get()));
497 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1));
498 controller->SetUpdateMoreTexturesTime(base::TimeDelta::FromMilliseconds(500));
499 controller->SetUpdateMoreTexturesSize(1);
501 for (int i = 0; i < 100; i++) {
502 if (client.ReadyToFinalizeCalled())
505 // Not enough time for any updates.
506 controller->PerformMoreUpdates(controller->Now() +
507 base::TimeDelta::FromMilliseconds(400));
509 if (task_runner->HasPendingTask())
510 RunPendingTask(task_runner.get(), controller.get());
513 EXPECT_FALSE(task_runner->HasPendingTask());
514 EXPECT_TRUE(client.ReadyToFinalizeCalled());
515 EXPECT_EQ(2, num_total_uploads_);