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/prioritized_resource.h" 6 7 #include "cc/resources/prioritized_resource_manager.h" 8 #include "cc/resources/resource.h" 9 #include "cc/test/fake_output_surface.h" 10 #include "cc/test/fake_proxy.h" 11 #include "cc/test/tiled_layer_test_common.h" 12 #include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 namespace cc { 16 17 class PrioritizedResourceTest : public testing::Test { 18 public: 19 PrioritizedResourceTest() 20 : texture_size_(256, 256), 21 texture_format_(GL_RGBA), 22 output_surface_(CreateFakeOutputSurface()) { 23 DebugScopedSetImplThread impl_thread(&proxy_); 24 resource_provider_ = cc::ResourceProvider::Create(output_surface_.get(), 0); 25 } 26 27 virtual ~PrioritizedResourceTest() { 28 DebugScopedSetImplThread impl_thread(&proxy_); 29 resource_provider_.reset(); 30 } 31 32 size_t TexturesMemorySize(size_t texture_count) { 33 return Resource::MemorySizeBytes(texture_size_, texture_format_) * 34 texture_count; 35 } 36 37 scoped_ptr<PrioritizedResourceManager> CreateManager(size_t max_textures) { 38 scoped_ptr<PrioritizedResourceManager> manager = 39 PrioritizedResourceManager::Create(&proxy_); 40 manager->SetMaxMemoryLimitBytes(TexturesMemorySize(max_textures)); 41 return manager.Pass(); 42 } 43 44 bool ValidateTexture(PrioritizedResource* texture, 45 bool request_late) { 46 ResourceManagerAssertInvariants(texture->resource_manager()); 47 if (request_late) 48 texture->RequestLate(); 49 ResourceManagerAssertInvariants(texture->resource_manager()); 50 DebugScopedSetImplThreadAndMainThreadBlocked 51 impl_thread_and_main_thread_blocked(&proxy_); 52 bool success = texture->can_acquire_backing_texture(); 53 if (success) 54 texture->AcquireBackingTexture(ResourceProvider()); 55 return success; 56 } 57 58 void PrioritizeTexturesAndBackings( 59 PrioritizedResourceManager* resource_manager) { 60 resource_manager->PrioritizeTextures(); 61 ResourceManagerUpdateBackingsPriorities(resource_manager); 62 } 63 64 void ResourceManagerUpdateBackingsPriorities( 65 PrioritizedResourceManager* resource_manager) { 66 DebugScopedSetImplThreadAndMainThreadBlocked 67 impl_thread_and_main_thread_blocked(&proxy_); 68 resource_manager->PushTexturePrioritiesToBackings(); 69 } 70 71 cc::ResourceProvider* ResourceProvider() { return resource_provider_.get(); } 72 73 void ResourceManagerAssertInvariants( 74 PrioritizedResourceManager* resource_manager) { 75 #ifndef NDEBUG 76 DebugScopedSetImplThreadAndMainThreadBlocked 77 impl_thread_and_main_thread_blocked(&proxy_); 78 resource_manager->AssertInvariants(); 79 #endif 80 } 81 82 bool TextureBackingIsAbovePriorityCutoff(PrioritizedResource* texture) { 83 return texture->backing()-> 84 was_above_priority_cutoff_at_last_priority_update(); 85 } 86 87 size_t EvictedBackingCount(PrioritizedResourceManager* resource_manager) { 88 return resource_manager->evicted_backings_.size(); 89 } 90 91 protected: 92 FakeProxy proxy_; 93 const gfx::Size texture_size_; 94 const GLenum texture_format_; 95 scoped_ptr<OutputSurface> output_surface_; 96 scoped_ptr<cc::ResourceProvider> resource_provider_; 97 }; 98 99 namespace { 100 101 TEST_F(PrioritizedResourceTest, RequestTextureExceedingMaxLimit) { 102 const size_t kMaxTextures = 8; 103 scoped_ptr<PrioritizedResourceManager> resource_manager = 104 CreateManager(kMaxTextures); 105 106 // Create textures for double our memory limit. 107 scoped_ptr<PrioritizedResource> textures[kMaxTextures * 2]; 108 109 for (size_t i = 0; i < kMaxTextures * 2; ++i) 110 textures[i] = 111 resource_manager->CreateTexture(texture_size_, texture_format_); 112 113 // Set decreasing priorities 114 for (size_t i = 0; i < kMaxTextures * 2; ++i) 115 textures[i]->set_request_priority(100 + i); 116 117 // Only lower half should be available. 118 PrioritizeTexturesAndBackings(resource_manager.get()); 119 EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); 120 EXPECT_TRUE(ValidateTexture(textures[7].get(), false)); 121 EXPECT_FALSE(ValidateTexture(textures[8].get(), false)); 122 EXPECT_FALSE(ValidateTexture(textures[15].get(), false)); 123 124 // Set increasing priorities 125 for (size_t i = 0; i < kMaxTextures * 2; ++i) 126 textures[i]->set_request_priority(100 - i); 127 128 // Only upper half should be available. 129 PrioritizeTexturesAndBackings(resource_manager.get()); 130 EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); 131 EXPECT_FALSE(ValidateTexture(textures[7].get(), false)); 132 EXPECT_TRUE(ValidateTexture(textures[8].get(), false)); 133 EXPECT_TRUE(ValidateTexture(textures[15].get(), false)); 134 135 EXPECT_EQ(TexturesMemorySize(kMaxTextures), 136 resource_manager->MemoryAboveCutoffBytes()); 137 EXPECT_LE(resource_manager->MemoryUseBytes(), 138 resource_manager->MemoryAboveCutoffBytes()); 139 EXPECT_EQ(TexturesMemorySize(2*kMaxTextures), 140 resource_manager->MaxMemoryNeededBytes()); 141 142 DebugScopedSetImplThreadAndMainThreadBlocked 143 impl_thread_and_main_thread_blocked(&proxy_); 144 resource_manager->ClearAllMemory(ResourceProvider()); 145 } 146 147 TEST_F(PrioritizedResourceTest, ChangeMemoryLimits) { 148 const size_t kMaxTextures = 8; 149 scoped_ptr<PrioritizedResourceManager> resource_manager = 150 CreateManager(kMaxTextures); 151 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 152 153 for (size_t i = 0; i < kMaxTextures; ++i) { 154 textures[i] = 155 resource_manager->CreateTexture(texture_size_, texture_format_); 156 } 157 for (size_t i = 0; i < kMaxTextures; ++i) 158 textures[i]->set_request_priority(100 + i); 159 160 // Set max limit to 8 textures 161 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); 162 PrioritizeTexturesAndBackings(resource_manager.get()); 163 for (size_t i = 0; i < kMaxTextures; ++i) 164 ValidateTexture(textures[i].get(), false); 165 { 166 DebugScopedSetImplThreadAndMainThreadBlocked 167 impl_thread_and_main_thread_blocked(&proxy_); 168 resource_manager->ReduceMemory(ResourceProvider()); 169 } 170 171 EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); 172 EXPECT_LE(resource_manager->MemoryUseBytes(), 173 resource_manager->MemoryAboveCutoffBytes()); 174 175 // Set max limit to 5 textures 176 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(5)); 177 PrioritizeTexturesAndBackings(resource_manager.get()); 178 for (size_t i = 0; i < kMaxTextures; ++i) 179 EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 5); 180 { 181 DebugScopedSetImplThreadAndMainThreadBlocked 182 impl_thread_and_main_thread_blocked(&proxy_); 183 resource_manager->ReduceMemory(ResourceProvider()); 184 } 185 186 EXPECT_EQ(TexturesMemorySize(5), resource_manager->MemoryAboveCutoffBytes()); 187 EXPECT_LE(resource_manager->MemoryUseBytes(), 188 resource_manager->MemoryAboveCutoffBytes()); 189 EXPECT_EQ(TexturesMemorySize(kMaxTextures), 190 resource_manager->MaxMemoryNeededBytes()); 191 192 // Set max limit to 4 textures 193 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(4)); 194 PrioritizeTexturesAndBackings(resource_manager.get()); 195 for (size_t i = 0; i < kMaxTextures; ++i) 196 EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); 197 { 198 DebugScopedSetImplThreadAndMainThreadBlocked 199 impl_thread_and_main_thread_blocked(&proxy_); 200 resource_manager->ReduceMemory(ResourceProvider()); 201 } 202 203 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); 204 EXPECT_LE(resource_manager->MemoryUseBytes(), 205 resource_manager->MemoryAboveCutoffBytes()); 206 EXPECT_EQ(TexturesMemorySize(kMaxTextures), 207 resource_manager->MaxMemoryNeededBytes()); 208 209 DebugScopedSetImplThreadAndMainThreadBlocked 210 impl_thread_and_main_thread_blocked(&proxy_); 211 resource_manager->ClearAllMemory(ResourceProvider()); 212 } 213 214 TEST_F(PrioritizedResourceTest, ChangePriorityCutoff) { 215 const size_t kMaxTextures = 8; 216 scoped_ptr<PrioritizedResourceManager> resource_manager = 217 CreateManager(kMaxTextures); 218 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 219 220 for (size_t i = 0; i < kMaxTextures; ++i) { 221 textures[i] = 222 resource_manager->CreateTexture(texture_size_, texture_format_); 223 } 224 for (size_t i = 0; i < kMaxTextures; ++i) 225 textures[i]->set_request_priority(100 + i); 226 227 // Set the cutoff to drop two textures. Try to request_late on all textures, 228 // and make sure that request_late doesn't work on a texture with equal 229 // priority to the cutoff. 230 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); 231 resource_manager->SetExternalPriorityCutoff(106); 232 PrioritizeTexturesAndBackings(resource_manager.get()); 233 for (size_t i = 0; i < kMaxTextures; ++i) 234 EXPECT_EQ(ValidateTexture(textures[i].get(), true), i < 6); 235 { 236 DebugScopedSetImplThreadAndMainThreadBlocked 237 impl_thread_and_main_thread_blocked(&proxy_); 238 resource_manager->ReduceMemory(ResourceProvider()); 239 } 240 EXPECT_EQ(TexturesMemorySize(6), resource_manager->MemoryAboveCutoffBytes()); 241 EXPECT_LE(resource_manager->MemoryUseBytes(), 242 resource_manager->MemoryAboveCutoffBytes()); 243 244 // Set the cutoff to drop two more textures. 245 resource_manager->SetExternalPriorityCutoff(104); 246 PrioritizeTexturesAndBackings(resource_manager.get()); 247 for (size_t i = 0; i < kMaxTextures; ++i) 248 EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); 249 { 250 DebugScopedSetImplThreadAndMainThreadBlocked 251 impl_thread_and_main_thread_blocked(&proxy_); 252 resource_manager->ReduceMemory(ResourceProvider()); 253 } 254 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); 255 256 // Do a one-time eviction for one more texture based on priority cutoff 257 PrioritizedResourceManager::BackingList evicted_backings; 258 resource_manager->UnlinkAndClearEvictedBackings(); 259 { 260 DebugScopedSetImplThreadAndMainThreadBlocked 261 impl_thread_and_main_thread_blocked(&proxy_); 262 resource_manager->ReduceMemoryOnImplThread( 263 TexturesMemorySize(8), 104, ResourceProvider()); 264 EXPECT_EQ(0u, EvictedBackingCount(resource_manager.get())); 265 resource_manager->ReduceMemoryOnImplThread( 266 TexturesMemorySize(8), 103, ResourceProvider()); 267 EXPECT_EQ(1u, EvictedBackingCount(resource_manager.get())); 268 } 269 resource_manager->UnlinkAndClearEvictedBackings(); 270 EXPECT_EQ(TexturesMemorySize(3), resource_manager->MemoryUseBytes()); 271 272 // Re-allocate the the texture after the one-time drop. 273 PrioritizeTexturesAndBackings(resource_manager.get()); 274 for (size_t i = 0; i < kMaxTextures; ++i) 275 EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); 276 { 277 DebugScopedSetImplThreadAndMainThreadBlocked 278 impl_thread_and_main_thread_blocked(&proxy_); 279 resource_manager->ReduceMemory(ResourceProvider()); 280 } 281 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); 282 283 DebugScopedSetImplThreadAndMainThreadBlocked 284 impl_thread_and_main_thread_blocked(&proxy_); 285 resource_manager->ClearAllMemory(ResourceProvider()); 286 } 287 288 TEST_F(PrioritizedResourceTest, ResourceManagerPartialUpdateTextures) { 289 const size_t kMaxTextures = 4; 290 const size_t kNumTextures = 4; 291 scoped_ptr<PrioritizedResourceManager> resource_manager = 292 CreateManager(kMaxTextures); 293 scoped_ptr<PrioritizedResource> textures[kNumTextures]; 294 scoped_ptr<PrioritizedResource> more_textures[kNumTextures]; 295 296 for (size_t i = 0; i < kNumTextures; ++i) { 297 textures[i] = 298 resource_manager->CreateTexture(texture_size_, texture_format_); 299 more_textures[i] = 300 resource_manager->CreateTexture(texture_size_, texture_format_); 301 } 302 303 for (size_t i = 0; i < kNumTextures; ++i) 304 textures[i]->set_request_priority(200 + i); 305 PrioritizeTexturesAndBackings(resource_manager.get()); 306 307 // Allocate textures which are currently high priority. 308 EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); 309 EXPECT_TRUE(ValidateTexture(textures[1].get(), false)); 310 EXPECT_TRUE(ValidateTexture(textures[2].get(), false)); 311 EXPECT_TRUE(ValidateTexture(textures[3].get(), false)); 312 313 EXPECT_TRUE(textures[0]->have_backing_texture()); 314 EXPECT_TRUE(textures[1]->have_backing_texture()); 315 EXPECT_TRUE(textures[2]->have_backing_texture()); 316 EXPECT_TRUE(textures[3]->have_backing_texture()); 317 318 for (size_t i = 0; i < kNumTextures; ++i) 319 more_textures[i]->set_request_priority(100 + i); 320 PrioritizeTexturesAndBackings(resource_manager.get()); 321 322 // Textures are now below cutoff. 323 EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); 324 EXPECT_FALSE(ValidateTexture(textures[1].get(), false)); 325 EXPECT_FALSE(ValidateTexture(textures[2].get(), false)); 326 EXPECT_FALSE(ValidateTexture(textures[3].get(), false)); 327 328 // But they are still valid to use. 329 EXPECT_TRUE(textures[0]->have_backing_texture()); 330 EXPECT_TRUE(textures[1]->have_backing_texture()); 331 EXPECT_TRUE(textures[2]->have_backing_texture()); 332 EXPECT_TRUE(textures[3]->have_backing_texture()); 333 334 // Higher priority textures are finally needed. 335 EXPECT_TRUE(ValidateTexture(more_textures[0].get(), false)); 336 EXPECT_TRUE(ValidateTexture(more_textures[1].get(), false)); 337 EXPECT_TRUE(ValidateTexture(more_textures[2].get(), false)); 338 EXPECT_TRUE(ValidateTexture(more_textures[3].get(), false)); 339 340 // Lower priority have been fully evicted. 341 EXPECT_FALSE(textures[0]->have_backing_texture()); 342 EXPECT_FALSE(textures[1]->have_backing_texture()); 343 EXPECT_FALSE(textures[2]->have_backing_texture()); 344 EXPECT_FALSE(textures[3]->have_backing_texture()); 345 346 DebugScopedSetImplThreadAndMainThreadBlocked 347 impl_thread_and_main_thread_blocked(&proxy_); 348 resource_manager->ClearAllMemory(ResourceProvider()); 349 } 350 351 TEST_F(PrioritizedResourceTest, ResourceManagerPrioritiesAreEqual) { 352 const size_t kMaxTextures = 16; 353 scoped_ptr<PrioritizedResourceManager> resource_manager = 354 CreateManager(kMaxTextures); 355 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 356 357 for (size_t i = 0; i < kMaxTextures; ++i) { 358 textures[i] = 359 resource_manager->CreateTexture(texture_size_, texture_format_); 360 } 361 362 // All 16 textures have the same priority except 2 higher priority. 363 for (size_t i = 0; i < kMaxTextures; ++i) 364 textures[i]->set_request_priority(100); 365 textures[0]->set_request_priority(99); 366 textures[1]->set_request_priority(99); 367 368 // Set max limit to 8 textures 369 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); 370 PrioritizeTexturesAndBackings(resource_manager.get()); 371 372 // The two high priority textures should be available, others should not. 373 for (size_t i = 0; i < 2; ++i) 374 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); 375 for (size_t i = 2; i < kMaxTextures; ++i) 376 EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); 377 EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryAboveCutoffBytes()); 378 EXPECT_LE(resource_manager->MemoryUseBytes(), 379 resource_manager->MemoryAboveCutoffBytes()); 380 381 // Manually reserving textures should only succeed on the higher priority 382 // textures, and on remaining textures up to the memory limit. 383 for (size_t i = 0; i < 8; i++) 384 EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); 385 for (size_t i = 9; i < kMaxTextures; i++) 386 EXPECT_FALSE(ValidateTexture(textures[i].get(), true)); 387 EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); 388 EXPECT_LE(resource_manager->MemoryUseBytes(), 389 resource_manager->MemoryAboveCutoffBytes()); 390 391 DebugScopedSetImplThreadAndMainThreadBlocked 392 impl_thread_and_main_thread_blocked(&proxy_); 393 resource_manager->ClearAllMemory(ResourceProvider()); 394 } 395 396 TEST_F(PrioritizedResourceTest, ResourceManagerDestroyedFirst) { 397 scoped_ptr<PrioritizedResourceManager> resource_manager = CreateManager(1); 398 scoped_ptr<PrioritizedResource> texture = 399 resource_manager->CreateTexture(texture_size_, texture_format_); 400 401 // Texture is initially invalid, but it will become available. 402 EXPECT_FALSE(texture->have_backing_texture()); 403 404 texture->set_request_priority(100); 405 PrioritizeTexturesAndBackings(resource_manager.get()); 406 407 EXPECT_TRUE(ValidateTexture(texture.get(), false)); 408 EXPECT_TRUE(texture->can_acquire_backing_texture()); 409 EXPECT_TRUE(texture->have_backing_texture()); 410 { 411 DebugScopedSetImplThreadAndMainThreadBlocked 412 impl_thread_and_main_thread_blocked(&proxy_); 413 resource_manager->ClearAllMemory(ResourceProvider()); 414 } 415 resource_manager.reset(); 416 417 EXPECT_FALSE(texture->can_acquire_backing_texture()); 418 EXPECT_FALSE(texture->have_backing_texture()); 419 } 420 421 TEST_F(PrioritizedResourceTest, TextureMovedToNewManager) { 422 scoped_ptr<PrioritizedResourceManager> resource_manager_one = 423 CreateManager(1); 424 scoped_ptr<PrioritizedResourceManager> resource_manager_two = 425 CreateManager(1); 426 scoped_ptr<PrioritizedResource> texture = 427 resource_manager_one->CreateTexture(texture_size_, texture_format_); 428 429 // Texture is initially invalid, but it will become available. 430 EXPECT_FALSE(texture->have_backing_texture()); 431 432 texture->set_request_priority(100); 433 PrioritizeTexturesAndBackings(resource_manager_one.get()); 434 435 EXPECT_TRUE(ValidateTexture(texture.get(), false)); 436 EXPECT_TRUE(texture->can_acquire_backing_texture()); 437 EXPECT_TRUE(texture->have_backing_texture()); 438 439 texture->SetTextureManager(NULL); 440 { 441 DebugScopedSetImplThreadAndMainThreadBlocked 442 impl_thread_and_main_thread_blocked(&proxy_); 443 resource_manager_one->ClearAllMemory(ResourceProvider()); 444 } 445 resource_manager_one.reset(); 446 447 EXPECT_FALSE(texture->can_acquire_backing_texture()); 448 EXPECT_FALSE(texture->have_backing_texture()); 449 450 texture->SetTextureManager(resource_manager_two.get()); 451 452 PrioritizeTexturesAndBackings(resource_manager_two.get()); 453 454 EXPECT_TRUE(ValidateTexture(texture.get(), false)); 455 EXPECT_TRUE(texture->can_acquire_backing_texture()); 456 EXPECT_TRUE(texture->have_backing_texture()); 457 458 DebugScopedSetImplThreadAndMainThreadBlocked 459 impl_thread_and_main_thread_blocked(&proxy_); 460 resource_manager_two->ClearAllMemory(ResourceProvider()); 461 } 462 463 TEST_F(PrioritizedResourceTest, 464 RenderSurfacesReduceMemoryAvailableOutsideRootSurface) { 465 const size_t kMaxTextures = 8; 466 scoped_ptr<PrioritizedResourceManager> resource_manager = 467 CreateManager(kMaxTextures); 468 469 // Half of the memory is taken by surfaces (with high priority place-holder) 470 scoped_ptr<PrioritizedResource> render_surface_place_holder = 471 resource_manager->CreateTexture(texture_size_, texture_format_); 472 render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( 473 TexturesMemorySize(4)); 474 render_surface_place_holder->set_request_priority( 475 PriorityCalculator::RenderSurfacePriority()); 476 477 // Create textures to fill our memory limit. 478 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 479 480 for (size_t i = 0; i < kMaxTextures; ++i) { 481 textures[i] = 482 resource_manager->CreateTexture(texture_size_, texture_format_); 483 } 484 485 // Set decreasing non-visible priorities outside root surface. 486 for (size_t i = 0; i < kMaxTextures; ++i) 487 textures[i]->set_request_priority(100 + i); 488 489 // Only lower half should be available. 490 PrioritizeTexturesAndBackings(resource_manager.get()); 491 EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); 492 EXPECT_TRUE(ValidateTexture(textures[3].get(), false)); 493 EXPECT_FALSE(ValidateTexture(textures[4].get(), false)); 494 EXPECT_FALSE(ValidateTexture(textures[7].get(), false)); 495 496 // Set increasing non-visible priorities outside root surface. 497 for (size_t i = 0; i < kMaxTextures; ++i) 498 textures[i]->set_request_priority(100 - i); 499 500 // Only upper half should be available. 501 PrioritizeTexturesAndBackings(resource_manager.get()); 502 EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); 503 EXPECT_FALSE(ValidateTexture(textures[3].get(), false)); 504 EXPECT_TRUE(ValidateTexture(textures[4].get(), false)); 505 EXPECT_TRUE(ValidateTexture(textures[7].get(), false)); 506 507 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); 508 EXPECT_EQ(TexturesMemorySize(4), 509 resource_manager->MemoryForSelfManagedTextures()); 510 EXPECT_LE(resource_manager->MemoryUseBytes(), 511 resource_manager->MemoryAboveCutoffBytes()); 512 EXPECT_EQ(TexturesMemorySize(8), 513 resource_manager->MaxMemoryNeededBytes()); 514 515 DebugScopedSetImplThreadAndMainThreadBlocked 516 impl_thread_and_main_thread_blocked(&proxy_); 517 resource_manager->ClearAllMemory(ResourceProvider()); 518 } 519 520 TEST_F(PrioritizedResourceTest, 521 RenderSurfacesReduceMemoryAvailableForRequestLate) { 522 const size_t kMaxTextures = 8; 523 scoped_ptr<PrioritizedResourceManager> resource_manager = 524 CreateManager(kMaxTextures); 525 526 // Half of the memory is taken by surfaces (with high priority place-holder) 527 scoped_ptr<PrioritizedResource> render_surface_place_holder = 528 resource_manager->CreateTexture(texture_size_, texture_format_); 529 render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( 530 TexturesMemorySize(4)); 531 render_surface_place_holder->set_request_priority( 532 PriorityCalculator::RenderSurfacePriority()); 533 534 // Create textures to fill our memory limit. 535 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 536 537 for (size_t i = 0; i < kMaxTextures; ++i) { 538 textures[i] = 539 resource_manager->CreateTexture(texture_size_, texture_format_); 540 } 541 542 // Set equal priorities. 543 for (size_t i = 0; i < kMaxTextures; ++i) 544 textures[i]->set_request_priority(100); 545 546 // The first four to be requested late will be available. 547 PrioritizeTexturesAndBackings(resource_manager.get()); 548 for (unsigned i = 0; i < kMaxTextures; ++i) 549 EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); 550 for (unsigned i = 0; i < kMaxTextures; i += 2) 551 EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); 552 for (unsigned i = 1; i < kMaxTextures; i += 2) 553 EXPECT_FALSE(ValidateTexture(textures[i].get(), true)); 554 555 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); 556 EXPECT_EQ(TexturesMemorySize(4), 557 resource_manager->MemoryForSelfManagedTextures()); 558 EXPECT_LE(resource_manager->MemoryUseBytes(), 559 resource_manager->MemoryAboveCutoffBytes()); 560 EXPECT_EQ(TexturesMemorySize(8), 561 resource_manager->MaxMemoryNeededBytes()); 562 563 DebugScopedSetImplThreadAndMainThreadBlocked 564 impl_thread_and_main_thread_blocked(&proxy_); 565 resource_manager->ClearAllMemory(ResourceProvider()); 566 } 567 568 TEST_F(PrioritizedResourceTest, 569 WhenRenderSurfaceNotAvailableTexturesAlsoNotAvailable) { 570 const size_t kMaxTextures = 8; 571 scoped_ptr<PrioritizedResourceManager> resource_manager = 572 CreateManager(kMaxTextures); 573 574 // Half of the memory is taken by surfaces (with high priority place-holder) 575 scoped_ptr<PrioritizedResource> render_surface_place_holder = 576 resource_manager->CreateTexture(texture_size_, texture_format_); 577 render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( 578 TexturesMemorySize(4)); 579 render_surface_place_holder->set_request_priority( 580 PriorityCalculator::RenderSurfacePriority()); 581 582 // Create textures to fill our memory limit. 583 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 584 585 for (size_t i = 0; i < kMaxTextures; ++i) 586 textures[i] = 587 resource_manager->CreateTexture(texture_size_, texture_format_); 588 589 // Set 6 visible textures in the root surface, and 2 in a child surface. 590 for (size_t i = 0; i < 6; ++i) { 591 textures[i]-> 592 set_request_priority(PriorityCalculator::VisiblePriority(true)); 593 } 594 for (size_t i = 6; i < 8; ++i) { 595 textures[i]-> 596 set_request_priority(PriorityCalculator::VisiblePriority(false)); 597 } 598 599 PrioritizeTexturesAndBackings(resource_manager.get()); 600 601 // Unable to request_late textures in the child surface. 602 EXPECT_FALSE(ValidateTexture(textures[6].get(), true)); 603 EXPECT_FALSE(ValidateTexture(textures[7].get(), true)); 604 605 // Root surface textures are valid. 606 for (size_t i = 0; i < 6; ++i) 607 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); 608 609 EXPECT_EQ(TexturesMemorySize(6), resource_manager->MemoryAboveCutoffBytes()); 610 EXPECT_EQ(TexturesMemorySize(2), 611 resource_manager->MemoryForSelfManagedTextures()); 612 EXPECT_LE(resource_manager->MemoryUseBytes(), 613 resource_manager->MemoryAboveCutoffBytes()); 614 615 DebugScopedSetImplThreadAndMainThreadBlocked 616 impl_thread_and_main_thread_blocked(&proxy_); 617 resource_manager->ClearAllMemory(ResourceProvider()); 618 } 619 620 TEST_F(PrioritizedResourceTest, RequestLateBackingsSorting) { 621 const size_t kMaxTextures = 8; 622 scoped_ptr<PrioritizedResourceManager> resource_manager = 623 CreateManager(kMaxTextures); 624 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); 625 626 // Create textures to fill our memory limit. 627 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 628 for (size_t i = 0; i < kMaxTextures; ++i) 629 textures[i] = 630 resource_manager->CreateTexture(texture_size_, texture_format_); 631 632 // Set equal priorities, and allocate backings for all textures. 633 for (size_t i = 0; i < kMaxTextures; ++i) 634 textures[i]->set_request_priority(100); 635 PrioritizeTexturesAndBackings(resource_manager.get()); 636 for (unsigned i = 0; i < kMaxTextures; ++i) 637 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); 638 639 // Drop the memory limit and prioritize (none will be above the threshold, 640 // but they still have backings because ReduceMemory hasn't been called). 641 resource_manager->SetMaxMemoryLimitBytes( 642 TexturesMemorySize(kMaxTextures / 2)); 643 PrioritizeTexturesAndBackings(resource_manager.get()); 644 645 // Push half of them back over the limit. 646 for (size_t i = 0; i < kMaxTextures; i += 2) 647 EXPECT_TRUE(textures[i]->RequestLate()); 648 649 // Push the priorities to the backings array and sort the backings array 650 ResourceManagerUpdateBackingsPriorities(resource_manager.get()); 651 652 // Assert that the backings list be sorted with the below-limit backings 653 // before the above-limit backings. 654 ResourceManagerAssertInvariants(resource_manager.get()); 655 656 // Make sure that we have backings for all of the textures. 657 for (size_t i = 0; i < kMaxTextures; ++i) 658 EXPECT_TRUE(textures[i]->have_backing_texture()); 659 660 // Make sure that only the request_late textures are above the priority 661 // cutoff 662 for (size_t i = 0; i < kMaxTextures; i += 2) 663 EXPECT_TRUE(TextureBackingIsAbovePriorityCutoff(textures[i].get())); 664 for (size_t i = 1; i < kMaxTextures; i += 2) 665 EXPECT_FALSE(TextureBackingIsAbovePriorityCutoff(textures[i].get())); 666 667 DebugScopedSetImplThreadAndMainThreadBlocked 668 impl_thread_and_main_thread_blocked(&proxy_); 669 resource_manager->ClearAllMemory(ResourceProvider()); 670 } 671 672 TEST_F(PrioritizedResourceTest, ClearUploadsToEvictedResources) { 673 const size_t kMaxTextures = 4; 674 scoped_ptr<PrioritizedResourceManager> resource_manager = 675 CreateManager(kMaxTextures); 676 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); 677 678 // Create textures to fill our memory limit. 679 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 680 681 for (size_t i = 0; i < kMaxTextures; ++i) 682 textures[i] = 683 resource_manager->CreateTexture(texture_size_, texture_format_); 684 685 // Set equal priorities, and allocate backings for all textures. 686 for (size_t i = 0; i < kMaxTextures; ++i) 687 textures[i]->set_request_priority(100); 688 PrioritizeTexturesAndBackings(resource_manager.get()); 689 for (unsigned i = 0; i < kMaxTextures; ++i) 690 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); 691 692 ResourceUpdateQueue queue; 693 DebugScopedSetImplThreadAndMainThreadBlocked 694 impl_thread_and_main_thread_blocked(&proxy_); 695 for (size_t i = 0; i < kMaxTextures; ++i) { 696 const ResourceUpdate upload = ResourceUpdate::Create( 697 textures[i].get(), NULL, gfx::Rect(), gfx::Rect(), gfx::Vector2d()); 698 queue.AppendFullUpload(upload); 699 } 700 701 // Make sure that we have backings for all of the textures. 702 for (size_t i = 0; i < kMaxTextures; ++i) 703 EXPECT_TRUE(textures[i]->have_backing_texture()); 704 705 queue.ClearUploadsToEvictedResources(); 706 EXPECT_EQ(4u, queue.FullUploadSize()); 707 708 resource_manager->ReduceMemoryOnImplThread( 709 TexturesMemorySize(1), 710 PriorityCalculator::AllowEverythingCutoff(), 711 ResourceProvider()); 712 queue.ClearUploadsToEvictedResources(); 713 EXPECT_EQ(1u, queue.FullUploadSize()); 714 715 resource_manager->ReduceMemoryOnImplThread( 716 0, PriorityCalculator::AllowEverythingCutoff(), ResourceProvider()); 717 queue.ClearUploadsToEvictedResources(); 718 EXPECT_EQ(0u, queue.FullUploadSize()); 719 } 720 721 TEST_F(PrioritizedResourceTest, UsageStatistics) { 722 const size_t kMaxTextures = 5; 723 scoped_ptr<PrioritizedResourceManager> resource_manager = 724 CreateManager(kMaxTextures); 725 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; 726 727 for (size_t i = 0; i < kMaxTextures; ++i) { 728 textures[i] = 729 resource_manager->CreateTexture(texture_size_, texture_format_); 730 } 731 732 textures[0]-> 733 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); 734 textures[1]-> 735 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff()); 736 textures[2]->set_request_priority( 737 PriorityCalculator::AllowVisibleAndNearbyCutoff() - 1); 738 textures[3]-> 739 set_request_priority(PriorityCalculator::AllowVisibleAndNearbyCutoff()); 740 textures[4]->set_request_priority( 741 PriorityCalculator::AllowVisibleAndNearbyCutoff() + 1); 742 743 // Set max limit to 2 textures. 744 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(2)); 745 PrioritizeTexturesAndBackings(resource_manager.get()); 746 747 // The first two textures should be available, others should not. 748 for (size_t i = 0; i < 2; ++i) 749 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); 750 for (size_t i = 2; i < kMaxTextures; ++i) 751 EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); 752 753 // Validate the statistics. 754 { 755 DebugScopedSetImplThread impl_thread(&proxy_); 756 EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); 757 EXPECT_EQ(TexturesMemorySize(1), resource_manager->MemoryVisibleBytes()); 758 EXPECT_EQ(TexturesMemorySize(3), 759 resource_manager->MemoryVisibleAndNearbyBytes()); 760 } 761 762 // Re-prioritize the textures, but do not push the values to backings. 763 textures[0]-> 764 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); 765 textures[1]-> 766 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); 767 textures[2]-> 768 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); 769 textures[3]->set_request_priority( 770 PriorityCalculator::AllowVisibleAndNearbyCutoff() - 1); 771 textures[4]-> 772 set_request_priority(PriorityCalculator::AllowVisibleAndNearbyCutoff()); 773 resource_manager->PrioritizeTextures(); 774 775 // Verify that we still see the old values. 776 { 777 DebugScopedSetImplThread impl_thread(&proxy_); 778 EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); 779 EXPECT_EQ(TexturesMemorySize(1), resource_manager->MemoryVisibleBytes()); 780 EXPECT_EQ(TexturesMemorySize(3), 781 resource_manager->MemoryVisibleAndNearbyBytes()); 782 } 783 784 // Push priorities to backings, and verify we see the new values. 785 { 786 DebugScopedSetImplThreadAndMainThreadBlocked 787 impl_thread_and_main_thread_blocked(&proxy_); 788 resource_manager->PushTexturePrioritiesToBackings(); 789 EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); 790 EXPECT_EQ(TexturesMemorySize(3), resource_manager->MemoryVisibleBytes()); 791 EXPECT_EQ(TexturesMemorySize(4), 792 resource_manager->MemoryVisibleAndNearbyBytes()); 793 } 794 795 DebugScopedSetImplThreadAndMainThreadBlocked 796 impl_thread_and_main_thread_blocked(&proxy_); 797 resource_manager->ClearAllMemory(ResourceProvider()); 798 } 799 800 } // namespace 801 } // namespace cc 802