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. 4 5#include "cc/resources/resource_update_controller.h" 6 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" 19 20using testing::Test; 21 22namespace cc { 23namespace { 24 25const int kFlushPeriodFull = 4; 26const int kFlushPeriodPartial = kFlushPeriodFull; 27 28class ResourceUpdateControllerTest; 29 30class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D { 31 public: 32 explicit WebGraphicsContext3DForUploadTest(ResourceUpdateControllerTest* test) 33 : test_(test) {} 34 35 virtual void flush() OVERRIDE; 36 virtual void shallowFlushCHROMIUM() OVERRIDE; 37 virtual void texSubImage2D(GLenum target, 38 GLint level, 39 GLint xoffset, 40 GLint yoffset, 41 GLsizei width, 42 GLsizei height, 43 GLenum format, 44 GLenum type, 45 const void* pixels) OVERRIDE; 46 47 virtual void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value) 48 OVERRIDE; 49 50 private: 51 ResourceUpdateControllerTest* test_; 52}; 53 54class ResourceUpdateControllerTest : public Test { 55 public: 56 ResourceUpdateControllerTest() 57 : proxy_(), 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) {} 69 70 virtual ~ResourceUpdateControllerTest() { 71 DebugScopedSetImplThreadAndMainThreadBlocked 72 impl_thread_and_main_thread_blocked(&proxy_); 73 resource_manager_->ClearAllMemory(resource_provider_.get()); 74 } 75 76 public: 77 void OnFlush() { 78 // Check for back-to-back flushes. 79 EXPECT_EQ(0, num_consecutive_flushes_) << "Back-to-back flushes detected."; 80 81 num_dangling_uploads_ = 0; 82 num_consecutive_flushes_++; 83 num_total_flushes_++; 84 } 85 86 void OnUpload() { 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."; 91 } else { 92 EXPECT_LT(num_dangling_uploads_, kFlushPeriodPartial) 93 << "Too many consecutive partial uploads detected."; 94 } 95 96 num_consecutive_flushes_ = 0; 97 num_dangling_uploads_++; 98 num_total_uploads_++; 99 } 100 101 bool IsQueryResultAvailable() { 102 if (!query_results_available_) 103 return false; 104 105 query_results_available_--; 106 return true; 107 } 108 109 protected: 110 virtual void SetUp() { 111 bitmap_.allocN32Pixels(300, 150); 112 113 for (int i = 0; i < 4; i++) { 114 textures_[i] = PrioritizedResource::Create(resource_manager_.get(), 115 gfx::Size(300, 150), 116 RGBA_8888); 117 textures_[i]-> 118 set_request_priority(PriorityCalculator::VisiblePriority(true)); 119 } 120 resource_manager_->PrioritizeTextures(); 121 122 output_surface_ = FakeOutputSurface::Create3d( 123 scoped_ptr<TestWebGraphicsContext3D>( 124 new WebGraphicsContext3DForUploadTest(this))); 125 CHECK(output_surface_->BindToClient(&output_surface_client_)); 126 127 shared_bitmap_manager_.reset(new TestSharedBitmapManager()); 128 resource_provider_ = ResourceProvider::Create( 129 output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, 130 false); 131 } 132 133 void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count, 134 int texture_index) { 135 full_upload_count_expected_ += count; 136 total_upload_count_expected_ += count; 137 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); 143 } 144 145 void AppendFullUploadsToUpdateQueue(int count) { 146 AppendFullUploadsOfIndexedTextureToUpdateQueue(count, 0); 147 } 148 149 void AppendPartialUploadsOfIndexedTextureToUpdateQueue(int count, 150 int texture_index) { 151 partial_count_expected_ += count; 152 total_upload_count_expected_ += count; 153 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); 159 } 160 161 void AppendPartialUploadsToUpdateQueue(int count) { 162 AppendPartialUploadsOfIndexedTextureToUpdateQueue(count, 0); 163 } 164 165 void SetMaxUploadCountPerUpdate(int count) { 166 max_upload_count_per_update_ = count; 167 } 168 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(), 175 queue_.Pass(), 176 resource_provider_.get()); 177 update_controller->Finalize(); 178 } 179 180 void MakeQueryResultAvailable() { query_results_available_++; } 181 182 protected: 183 // Classes required to interact and test the ResourceUpdateController 184 FakeProxy proxy_; 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_; 192 SkBitmap bitmap_; 193 int query_results_available_; 194 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_; 200 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_; 206}; 207 208void WebGraphicsContext3DForUploadTest::flush() { test_->OnFlush(); } 209 210void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM() { 211 test_->OnFlush(); 212} 213 214void WebGraphicsContext3DForUploadTest::texSubImage2D(GLenum target, 215 GLint level, 216 GLint xoffset, 217 GLint yoffset, 218 GLsizei width, 219 GLsizei height, 220 GLenum format, 221 GLenum type, 222 const void* pixels) { 223 test_->OnUpload(); 224} 225 226void WebGraphicsContext3DForUploadTest::getQueryObjectuivEXT(GLuint id, 227 GLenum pname, 228 GLuint* params) { 229 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT) 230 *params = test_->IsQueryResultAvailable(); 231} 232 233// ZERO UPLOADS TESTS 234TEST_F(ResourceUpdateControllerTest, ZeroUploads) { 235 AppendFullUploadsToUpdateQueue(0); 236 AppendPartialUploadsToUpdateQueue(0); 237 UpdateTextures(); 238 239 EXPECT_EQ(0, num_total_flushes_); 240 EXPECT_EQ(0, num_total_uploads_); 241} 242 243// ONE UPLOAD TESTS 244TEST_F(ResourceUpdateControllerTest, OneFullUpload) { 245 AppendFullUploadsToUpdateQueue(1); 246 AppendPartialUploadsToUpdateQueue(0); 247 UpdateTextures(); 248 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."; 253} 254 255TEST_F(ResourceUpdateControllerTest, OnePartialUpload) { 256 AppendFullUploadsToUpdateQueue(0); 257 AppendPartialUploadsToUpdateQueue(1); 258 UpdateTextures(); 259 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."; 264} 265 266TEST_F(ResourceUpdateControllerTest, OneFullOnePartialUpload) { 267 AppendFullUploadsToUpdateQueue(1); 268 AppendPartialUploadsToUpdateQueue(1); 269 UpdateTextures(); 270 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."; 275} 276 277// This class of tests upload a number of textures that is a multiple 278// of the flush period. 279const int full_upload_flush_multipler = 7; 280const int full_count = full_upload_flush_multipler * kFlushPeriodFull; 281 282const int partial_upload_flush_multipler = 11; 283const int partial_count = 284 partial_upload_flush_multipler * kFlushPeriodPartial; 285 286TEST_F(ResourceUpdateControllerTest, ManyFullUploads) { 287 AppendFullUploadsToUpdateQueue(full_count); 288 AppendPartialUploadsToUpdateQueue(0); 289 UpdateTextures(); 290 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."; 295} 296 297TEST_F(ResourceUpdateControllerTest, ManyPartialUploads) { 298 AppendFullUploadsToUpdateQueue(0); 299 AppendPartialUploadsToUpdateQueue(partial_count); 300 UpdateTextures(); 301 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."; 306} 307 308TEST_F(ResourceUpdateControllerTest, ManyFullManyPartialUploads) { 309 AppendFullUploadsToUpdateQueue(full_count); 310 AppendPartialUploadsToUpdateQueue(partial_count); 311 UpdateTextures(); 312 313 EXPECT_EQ(full_upload_flush_multipler + partial_upload_flush_multipler, 314 num_total_flushes_); 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."; 318} 319 320class FakeResourceUpdateControllerClient 321 : public ResourceUpdateControllerClient { 322 public: 323 FakeResourceUpdateControllerClient() { Reset(); } 324 void Reset() { ready_to_finalize_called_ = false; } 325 bool ReadyToFinalizeCalled() const { return ready_to_finalize_called_; } 326 327 virtual void ReadyToFinalizeTextureUpdates() OVERRIDE { 328 ready_to_finalize_called_ = true; 329 } 330 331 protected: 332 bool ready_to_finalize_called_; 333}; 334 335class FakeResourceUpdateController : public ResourceUpdateController { 336 public: 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)); 344 } 345 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; 350 } 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_; 355 } 356 void SetUpdateMoreTexturesSize(size_t size) { 357 update_more_textures_size_ = size; 358 } 359 virtual size_t UpdateMoreTexturesSize() const OVERRIDE { 360 return update_more_textures_size_; 361 } 362 363 protected: 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) {} 372 373 ResourceProvider* resource_provider_; 374 base::TimeTicks now_; 375 base::TimeDelta update_textures_time_; 376 size_t update_more_textures_size_; 377}; 378 379static 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(); 384} 385 386TEST_F(ResourceUpdateControllerTest, UpdateMoreTextures) { 387 FakeResourceUpdateControllerClient client; 388 scoped_refptr<base::TestSimpleTaskRunner> task_runner = 389 new base::TestSimpleTaskRunner; 390 391 SetMaxUploadCountPerUpdate(1); 392 AppendFullUploadsToUpdateQueue(3); 393 AppendPartialUploadsToUpdateQueue(0); 394 395 DebugScopedSetImplThreadAndMainThreadBlocked 396 impl_thread_and_main_thread_blocked(&proxy_); 397 scoped_ptr<FakeResourceUpdateController> controller( 398 FakeResourceUpdateController::Create(&client, 399 task_runner.get(), 400 queue_.Pass(), 401 resource_provider_.get())); 402 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()); 410 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_); 418 419 // Complete one upload. 420 MakeQueryResultAvailable(); 421 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_); 431} 432 433TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) { 434 FakeResourceUpdateControllerClient client; 435 scoped_refptr<base::TestSimpleTaskRunner> task_runner = 436 new base::TestSimpleTaskRunner; 437 438 SetMaxUploadCountPerUpdate(1); 439 AppendFullUploadsToUpdateQueue(2); 440 AppendPartialUploadsToUpdateQueue(0); 441 442 DebugScopedSetImplThreadAndMainThreadBlocked 443 impl_thread_and_main_thread_blocked(&proxy_); 444 scoped_ptr<FakeResourceUpdateController> controller( 445 FakeResourceUpdateController::Create(&client, 446 task_runner.get(), 447 queue_.Pass(), 448 resource_provider_.get())); 449 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_); 460 461 client.Reset(); 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)); 467 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_); 472} 473 474TEST_F(ResourceUpdateControllerTest, UpdatesCompleteInFiniteTime) { 475 FakeResourceUpdateControllerClient client; 476 scoped_refptr<base::TestSimpleTaskRunner> task_runner = 477 new base::TestSimpleTaskRunner; 478 479 SetMaxUploadCountPerUpdate(1); 480 AppendFullUploadsToUpdateQueue(2); 481 AppendPartialUploadsToUpdateQueue(0); 482 483 DebugScopedSetImplThreadAndMainThreadBlocked 484 impl_thread_and_main_thread_blocked(&proxy_); 485 scoped_ptr<FakeResourceUpdateController> controller( 486 FakeResourceUpdateController::Create(&client, 487 task_runner.get(), 488 queue_.Pass(), 489 resource_provider_.get())); 490 491 controller->SetNow(controller->Now() + base::TimeDelta::FromMilliseconds(1)); 492 controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(500)); 493 controller->SetUpdateMoreTexturesSize(1); 494 495 for (int i = 0; i < 100; i++) { 496 if (client.ReadyToFinalizeCalled()) 497 break; 498 499 // Not enough time for any updates. 500 controller->PerformMoreUpdates(controller->Now() + 501 base::TimeDelta::FromMilliseconds(400)); 502 503 if (task_runner->HasPendingTask()) 504 RunPendingTask(task_runner.get(), controller.get()); 505 } 506 507 EXPECT_FALSE(task_runner->HasPendingTask()); 508 EXPECT_TRUE(client.ReadyToFinalizeCalled()); 509 EXPECT_EQ(2, num_total_uploads_); 510} 511 512} // namespace 513} // namespace cc 514