| OLD | NEW |
| (Empty) |
| 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 <vector> | |
| 8 | |
| 9 #include "cc/resources/prioritized_resource_manager.h" | |
| 10 #include "cc/resources/resource.h" | |
| 11 #include "cc/resources/resource_provider.h" | |
| 12 #include "cc/test/fake_output_surface.h" | |
| 13 #include "cc/test/fake_output_surface_client.h" | |
| 14 #include "cc/test/fake_proxy.h" | |
| 15 #include "cc/test/test_shared_bitmap_manager.h" | |
| 16 #include "cc/test/tiled_layer_test_common.h" | |
| 17 #include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 | |
| 20 namespace cc { | |
| 21 | |
| 22 class PrioritizedResourceTest : public testing::Test { | |
| 23 public: | |
| 24 PrioritizedResourceTest() | |
| 25 : texture_size_(256, 256), | |
| 26 texture_format_(RGBA_8888), | |
| 27 output_surface_(FakeOutputSurface::Create3d()) { | |
| 28 DebugScopedSetImplThread impl_thread(&proxy_); | |
| 29 CHECK(output_surface_->BindToClient(&output_surface_client_)); | |
| 30 shared_bitmap_manager_.reset(new TestSharedBitmapManager()); | |
| 31 resource_provider_ = ResourceProvider::Create(output_surface_.get(), | |
| 32 shared_bitmap_manager_.get(), | |
| 33 NULL, | |
| 34 NULL, | |
| 35 0, | |
| 36 false, | |
| 37 1); | |
| 38 } | |
| 39 | |
| 40 ~PrioritizedResourceTest() override { | |
| 41 DebugScopedSetImplThread impl_thread(&proxy_); | |
| 42 resource_provider_ = nullptr; | |
| 43 } | |
| 44 | |
| 45 size_t TexturesMemorySize(size_t texture_count) { | |
| 46 return Resource::MemorySizeBytes(texture_size_, texture_format_) * | |
| 47 texture_count; | |
| 48 } | |
| 49 | |
| 50 scoped_ptr<PrioritizedResourceManager> CreateManager(size_t max_textures) { | |
| 51 scoped_ptr<PrioritizedResourceManager> manager = | |
| 52 PrioritizedResourceManager::Create(&proxy_); | |
| 53 manager->SetMaxMemoryLimitBytes(TexturesMemorySize(max_textures)); | |
| 54 return manager.Pass(); | |
| 55 } | |
| 56 | |
| 57 bool ValidateTexture(PrioritizedResource* texture, | |
| 58 bool request_late) { | |
| 59 ResourceManagerAssertInvariants(texture->resource_manager()); | |
| 60 if (request_late) | |
| 61 texture->RequestLate(); | |
| 62 ResourceManagerAssertInvariants(texture->resource_manager()); | |
| 63 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 64 impl_thread_and_main_thread_blocked(&proxy_); | |
| 65 bool success = texture->can_acquire_backing_texture(); | |
| 66 if (success) | |
| 67 texture->AcquireBackingTexture(resource_provider()); | |
| 68 return success; | |
| 69 } | |
| 70 | |
| 71 void PrioritizeTexturesAndBackings( | |
| 72 PrioritizedResourceManager* resource_manager) { | |
| 73 resource_manager->PrioritizeTextures(); | |
| 74 ResourceManagerUpdateBackingsPriorities(resource_manager); | |
| 75 } | |
| 76 | |
| 77 void ResourceManagerUpdateBackingsPriorities( | |
| 78 PrioritizedResourceManager* resource_manager) { | |
| 79 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 80 impl_thread_and_main_thread_blocked(&proxy_); | |
| 81 resource_manager->PushTexturePrioritiesToBackings(); | |
| 82 } | |
| 83 | |
| 84 ResourceProvider* resource_provider() { return resource_provider_.get(); } | |
| 85 | |
| 86 void ResourceManagerAssertInvariants( | |
| 87 PrioritizedResourceManager* resource_manager) { | |
| 88 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 89 impl_thread_and_main_thread_blocked(&proxy_); | |
| 90 resource_manager->AssertInvariants(); | |
| 91 } | |
| 92 | |
| 93 bool TextureBackingIsAbovePriorityCutoff(PrioritizedResource* texture) { | |
| 94 return texture->backing()-> | |
| 95 was_above_priority_cutoff_at_last_priority_update(); | |
| 96 } | |
| 97 | |
| 98 size_t EvictedBackingCount(PrioritizedResourceManager* resource_manager) { | |
| 99 return resource_manager->evicted_backings_.size(); | |
| 100 } | |
| 101 | |
| 102 std::vector<unsigned> BackingResources( | |
| 103 PrioritizedResourceManager* resource_manager) { | |
| 104 std::vector<unsigned> resources; | |
| 105 for (PrioritizedResourceManager::BackingList::iterator it = | |
| 106 resource_manager->backings_.begin(); | |
| 107 it != resource_manager->backings_.end(); | |
| 108 ++it) | |
| 109 resources.push_back((*it)->id()); | |
| 110 return resources; | |
| 111 } | |
| 112 | |
| 113 protected: | |
| 114 FakeProxy proxy_; | |
| 115 const gfx::Size texture_size_; | |
| 116 const ResourceFormat texture_format_; | |
| 117 FakeOutputSurfaceClient output_surface_client_; | |
| 118 scoped_ptr<OutputSurface> output_surface_; | |
| 119 scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; | |
| 120 scoped_ptr<ResourceProvider> resource_provider_; | |
| 121 }; | |
| 122 | |
| 123 namespace { | |
| 124 | |
| 125 TEST_F(PrioritizedResourceTest, RequestTextureExceedingMaxLimit) { | |
| 126 const size_t kMaxTextures = 8; | |
| 127 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 128 CreateManager(kMaxTextures); | |
| 129 | |
| 130 // Create textures for double our memory limit. | |
| 131 scoped_ptr<PrioritizedResource> textures[kMaxTextures * 2]; | |
| 132 | |
| 133 for (size_t i = 0; i < kMaxTextures * 2; ++i) | |
| 134 textures[i] = | |
| 135 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 136 | |
| 137 // Set decreasing priorities | |
| 138 for (size_t i = 0; i < kMaxTextures * 2; ++i) | |
| 139 textures[i]->set_request_priority(100 + i); | |
| 140 | |
| 141 // Only lower half should be available. | |
| 142 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 143 EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); | |
| 144 EXPECT_TRUE(ValidateTexture(textures[7].get(), false)); | |
| 145 EXPECT_FALSE(ValidateTexture(textures[8].get(), false)); | |
| 146 EXPECT_FALSE(ValidateTexture(textures[15].get(), false)); | |
| 147 | |
| 148 // Set increasing priorities | |
| 149 for (size_t i = 0; i < kMaxTextures * 2; ++i) | |
| 150 textures[i]->set_request_priority(100 - i); | |
| 151 | |
| 152 // Only upper half should be available. | |
| 153 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 154 EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); | |
| 155 EXPECT_FALSE(ValidateTexture(textures[7].get(), false)); | |
| 156 EXPECT_TRUE(ValidateTexture(textures[8].get(), false)); | |
| 157 EXPECT_TRUE(ValidateTexture(textures[15].get(), false)); | |
| 158 | |
| 159 EXPECT_EQ(TexturesMemorySize(kMaxTextures), | |
| 160 resource_manager->MemoryAboveCutoffBytes()); | |
| 161 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 162 resource_manager->MemoryAboveCutoffBytes()); | |
| 163 EXPECT_EQ(TexturesMemorySize(2*kMaxTextures), | |
| 164 resource_manager->MaxMemoryNeededBytes()); | |
| 165 | |
| 166 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 167 impl_thread_and_main_thread_blocked(&proxy_); | |
| 168 resource_manager->ClearAllMemory(resource_provider()); | |
| 169 } | |
| 170 | |
| 171 TEST_F(PrioritizedResourceTest, ChangeMemoryLimits) { | |
| 172 const size_t kMaxTextures = 8; | |
| 173 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 174 CreateManager(kMaxTextures); | |
| 175 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 176 | |
| 177 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 178 textures[i] = | |
| 179 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 180 } | |
| 181 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 182 textures[i]->set_request_priority(100 + i); | |
| 183 | |
| 184 // Set max limit to 8 textures | |
| 185 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); | |
| 186 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 187 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 188 ValidateTexture(textures[i].get(), false); | |
| 189 { | |
| 190 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 191 impl_thread_and_main_thread_blocked(&proxy_); | |
| 192 resource_manager->ReduceMemory(resource_provider()); | |
| 193 } | |
| 194 | |
| 195 EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); | |
| 196 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 197 resource_manager->MemoryAboveCutoffBytes()); | |
| 198 | |
| 199 // Set max limit to 5 textures | |
| 200 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(5)); | |
| 201 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 202 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 203 EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 5); | |
| 204 { | |
| 205 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 206 impl_thread_and_main_thread_blocked(&proxy_); | |
| 207 resource_manager->ReduceMemory(resource_provider()); | |
| 208 } | |
| 209 | |
| 210 EXPECT_EQ(TexturesMemorySize(5), resource_manager->MemoryAboveCutoffBytes()); | |
| 211 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 212 resource_manager->MemoryAboveCutoffBytes()); | |
| 213 EXPECT_EQ(TexturesMemorySize(kMaxTextures), | |
| 214 resource_manager->MaxMemoryNeededBytes()); | |
| 215 | |
| 216 // Set max limit to 4 textures | |
| 217 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(4)); | |
| 218 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 219 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 220 EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); | |
| 221 { | |
| 222 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 223 impl_thread_and_main_thread_blocked(&proxy_); | |
| 224 resource_manager->ReduceMemory(resource_provider()); | |
| 225 } | |
| 226 | |
| 227 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); | |
| 228 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 229 resource_manager->MemoryAboveCutoffBytes()); | |
| 230 EXPECT_EQ(TexturesMemorySize(kMaxTextures), | |
| 231 resource_manager->MaxMemoryNeededBytes()); | |
| 232 | |
| 233 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 234 impl_thread_and_main_thread_blocked(&proxy_); | |
| 235 resource_manager->ClearAllMemory(resource_provider()); | |
| 236 } | |
| 237 | |
| 238 TEST_F(PrioritizedResourceTest, ReduceWastedMemory) { | |
| 239 const size_t kMaxTextures = 20; | |
| 240 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 241 CreateManager(kMaxTextures); | |
| 242 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 243 | |
| 244 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 245 textures[i] = | |
| 246 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 247 } | |
| 248 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 249 textures[i]->set_request_priority(100 + i); | |
| 250 | |
| 251 // Set the memory limit to the max number of textures. | |
| 252 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); | |
| 253 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 254 | |
| 255 // Create backings and textures for all of the textures. | |
| 256 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 257 ValidateTexture(textures[i].get(), false); | |
| 258 | |
| 259 { | |
| 260 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 261 impl_thread_and_main_thread_blocked(&proxy_); | |
| 262 uint8_t image[4] = {0}; | |
| 263 textures[i]->SetPixels(resource_provider_.get(), | |
| 264 image, | |
| 265 gfx::Rect(1, 1), | |
| 266 gfx::Rect(1, 1), | |
| 267 gfx::Vector2d()); | |
| 268 } | |
| 269 } | |
| 270 { | |
| 271 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 272 impl_thread_and_main_thread_blocked(&proxy_); | |
| 273 resource_manager->ReduceMemory(resource_provider()); | |
| 274 } | |
| 275 | |
| 276 // 20 textures have backings allocated. | |
| 277 EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); | |
| 278 | |
| 279 // Destroy one texture, not enough is wasted to cause cleanup. | |
| 280 textures[0] = nullptr; | |
| 281 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 282 { | |
| 283 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 284 impl_thread_and_main_thread_blocked(&proxy_); | |
| 285 resource_manager->UpdateBackingsState(resource_provider()); | |
| 286 resource_manager->ReduceWastedMemory(resource_provider()); | |
| 287 } | |
| 288 EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); | |
| 289 | |
| 290 // Destroy half the textures, leaving behind the backings. Now a cleanup | |
| 291 // should happen. | |
| 292 for (size_t i = 0; i < kMaxTextures / 2; ++i) | |
| 293 textures[i] = nullptr; | |
| 294 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 295 { | |
| 296 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 297 impl_thread_and_main_thread_blocked(&proxy_); | |
| 298 resource_manager->UpdateBackingsState(resource_provider()); | |
| 299 resource_manager->ReduceWastedMemory(resource_provider()); | |
| 300 } | |
| 301 EXPECT_GT(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); | |
| 302 | |
| 303 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 304 impl_thread_and_main_thread_blocked(&proxy_); | |
| 305 resource_manager->ClearAllMemory(resource_provider()); | |
| 306 } | |
| 307 | |
| 308 TEST_F(PrioritizedResourceTest, InUseNotWastedMemory) { | |
| 309 const size_t kMaxTextures = 20; | |
| 310 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 311 CreateManager(kMaxTextures); | |
| 312 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 313 | |
| 314 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 315 textures[i] = | |
| 316 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 317 } | |
| 318 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 319 textures[i]->set_request_priority(100 + i); | |
| 320 | |
| 321 // Set the memory limit to the max number of textures. | |
| 322 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); | |
| 323 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 324 | |
| 325 // Create backings and textures for all of the textures. | |
| 326 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 327 ValidateTexture(textures[i].get(), false); | |
| 328 | |
| 329 { | |
| 330 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 331 impl_thread_and_main_thread_blocked(&proxy_); | |
| 332 uint8_t image[4] = {0}; | |
| 333 textures[i]->SetPixels(resource_provider_.get(), | |
| 334 image, | |
| 335 gfx::Rect(1, 1), | |
| 336 gfx::Rect(1, 1), | |
| 337 gfx::Vector2d()); | |
| 338 } | |
| 339 } | |
| 340 { | |
| 341 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 342 impl_thread_and_main_thread_blocked(&proxy_); | |
| 343 resource_manager->ReduceMemory(resource_provider()); | |
| 344 } | |
| 345 | |
| 346 // 20 textures have backings allocated. | |
| 347 EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); | |
| 348 | |
| 349 // Send half the textures to a parent compositor. | |
| 350 ResourceProvider::ResourceIdArray to_send; | |
| 351 TransferableResourceArray transferable; | |
| 352 for (size_t i = 0; i < kMaxTextures / 2; ++i) | |
| 353 to_send.push_back(textures[i]->resource_id()); | |
| 354 resource_provider_->PrepareSendToParent(to_send, &transferable); | |
| 355 | |
| 356 // Destroy half the textures, leaving behind the backings. The backings are | |
| 357 // sent to a parent compositor though, so they should not be considered wasted | |
| 358 // and a cleanup should not happen. | |
| 359 for (size_t i = 0; i < kMaxTextures / 2; ++i) | |
| 360 textures[i] = nullptr; | |
| 361 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 362 { | |
| 363 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 364 impl_thread_and_main_thread_blocked(&proxy_); | |
| 365 resource_manager->UpdateBackingsState(resource_provider()); | |
| 366 resource_manager->ReduceWastedMemory(resource_provider()); | |
| 367 } | |
| 368 EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); | |
| 369 | |
| 370 // Receive the textures back from the parent compositor. Now a cleanup should | |
| 371 // happen. | |
| 372 ReturnedResourceArray returns; | |
| 373 TransferableResource::ReturnResources(transferable, &returns); | |
| 374 resource_provider_->ReceiveReturnsFromParent(returns); | |
| 375 { | |
| 376 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 377 impl_thread_and_main_thread_blocked(&proxy_); | |
| 378 resource_manager->UpdateBackingsState(resource_provider()); | |
| 379 resource_manager->ReduceWastedMemory(resource_provider()); | |
| 380 } | |
| 381 EXPECT_GT(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); | |
| 382 | |
| 383 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 384 impl_thread_and_main_thread_blocked(&proxy_); | |
| 385 resource_manager->ClearAllMemory(resource_provider()); | |
| 386 } | |
| 387 | |
| 388 TEST_F(PrioritizedResourceTest, ChangePriorityCutoff) { | |
| 389 const size_t kMaxTextures = 8; | |
| 390 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 391 CreateManager(kMaxTextures); | |
| 392 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 393 | |
| 394 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 395 textures[i] = | |
| 396 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 397 } | |
| 398 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 399 textures[i]->set_request_priority(100 + i); | |
| 400 | |
| 401 // Set the cutoff to drop two textures. Try to request_late on all textures, | |
| 402 // and make sure that request_late doesn't work on a texture with equal | |
| 403 // priority to the cutoff. | |
| 404 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); | |
| 405 resource_manager->SetExternalPriorityCutoff(106); | |
| 406 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 407 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 408 EXPECT_EQ(ValidateTexture(textures[i].get(), true), i < 6); | |
| 409 { | |
| 410 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 411 impl_thread_and_main_thread_blocked(&proxy_); | |
| 412 resource_manager->ReduceMemory(resource_provider()); | |
| 413 } | |
| 414 EXPECT_EQ(TexturesMemorySize(6), resource_manager->MemoryAboveCutoffBytes()); | |
| 415 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 416 resource_manager->MemoryAboveCutoffBytes()); | |
| 417 | |
| 418 // Set the cutoff to drop two more textures. | |
| 419 resource_manager->SetExternalPriorityCutoff(104); | |
| 420 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 421 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 422 EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); | |
| 423 { | |
| 424 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 425 impl_thread_and_main_thread_blocked(&proxy_); | |
| 426 resource_manager->ReduceMemory(resource_provider()); | |
| 427 } | |
| 428 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); | |
| 429 | |
| 430 // Do a one-time eviction for one more texture based on priority cutoff | |
| 431 resource_manager->UnlinkAndClearEvictedBackings(); | |
| 432 { | |
| 433 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 434 impl_thread_and_main_thread_blocked(&proxy_); | |
| 435 resource_manager->ReduceMemoryOnImplThread( | |
| 436 TexturesMemorySize(8), 104, resource_provider()); | |
| 437 EXPECT_EQ(0u, EvictedBackingCount(resource_manager.get())); | |
| 438 resource_manager->ReduceMemoryOnImplThread( | |
| 439 TexturesMemorySize(8), 103, resource_provider()); | |
| 440 EXPECT_EQ(1u, EvictedBackingCount(resource_manager.get())); | |
| 441 } | |
| 442 resource_manager->UnlinkAndClearEvictedBackings(); | |
| 443 EXPECT_EQ(TexturesMemorySize(3), resource_manager->MemoryUseBytes()); | |
| 444 | |
| 445 // Re-allocate the the texture after the one-time drop. | |
| 446 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 447 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 448 EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); | |
| 449 { | |
| 450 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 451 impl_thread_and_main_thread_blocked(&proxy_); | |
| 452 resource_manager->ReduceMemory(resource_provider()); | |
| 453 } | |
| 454 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); | |
| 455 | |
| 456 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 457 impl_thread_and_main_thread_blocked(&proxy_); | |
| 458 resource_manager->ClearAllMemory(resource_provider()); | |
| 459 } | |
| 460 | |
| 461 TEST_F(PrioritizedResourceTest, EvictingTexturesInParent) { | |
| 462 const size_t kMaxTextures = 8; | |
| 463 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 464 CreateManager(kMaxTextures); | |
| 465 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 466 unsigned texture_resource_ids[kMaxTextures]; | |
| 467 | |
| 468 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 469 textures[i] = | |
| 470 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 471 textures[i]->set_request_priority(100 + i); | |
| 472 } | |
| 473 | |
| 474 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 475 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 476 EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); | |
| 477 | |
| 478 { | |
| 479 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 480 impl_thread_and_main_thread_blocked(&proxy_); | |
| 481 uint8_t image[4] = {0}; | |
| 482 textures[i]->SetPixels(resource_provider_.get(), | |
| 483 image, | |
| 484 gfx::Rect(1, 1), | |
| 485 gfx::Rect(1, 1), | |
| 486 gfx::Vector2d()); | |
| 487 } | |
| 488 } | |
| 489 { | |
| 490 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 491 impl_thread_and_main_thread_blocked(&proxy_); | |
| 492 resource_manager->ReduceMemory(resource_provider()); | |
| 493 } | |
| 494 EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); | |
| 495 | |
| 496 for (size_t i = 0; i < 8; ++i) | |
| 497 texture_resource_ids[i] = textures[i]->resource_id(); | |
| 498 | |
| 499 // Evict four textures. It will be the last four. | |
| 500 { | |
| 501 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 502 impl_thread_and_main_thread_blocked(&proxy_); | |
| 503 resource_manager->ReduceMemoryOnImplThread( | |
| 504 TexturesMemorySize(4), 200, resource_provider()); | |
| 505 | |
| 506 EXPECT_EQ(4u, EvictedBackingCount(resource_manager.get())); | |
| 507 | |
| 508 // The last four backings are evicted. | |
| 509 std::vector<unsigned> remaining = BackingResources(resource_manager.get()); | |
| 510 EXPECT_TRUE(std::find(remaining.begin(), | |
| 511 remaining.end(), | |
| 512 texture_resource_ids[0]) != remaining.end()); | |
| 513 EXPECT_TRUE(std::find(remaining.begin(), | |
| 514 remaining.end(), | |
| 515 texture_resource_ids[1]) != remaining.end()); | |
| 516 EXPECT_TRUE(std::find(remaining.begin(), | |
| 517 remaining.end(), | |
| 518 texture_resource_ids[2]) != remaining.end()); | |
| 519 EXPECT_TRUE(std::find(remaining.begin(), | |
| 520 remaining.end(), | |
| 521 texture_resource_ids[3]) != remaining.end()); | |
| 522 } | |
| 523 resource_manager->UnlinkAndClearEvictedBackings(); | |
| 524 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryUseBytes()); | |
| 525 | |
| 526 // Re-allocate the the texture after the eviction. | |
| 527 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 528 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 529 EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); | |
| 530 | |
| 531 { | |
| 532 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 533 impl_thread_and_main_thread_blocked(&proxy_); | |
| 534 uint8_t image[4] = {0}; | |
| 535 textures[i]->SetPixels(resource_provider_.get(), | |
| 536 image, | |
| 537 gfx::Rect(1, 1), | |
| 538 gfx::Rect(1, 1), | |
| 539 gfx::Vector2d()); | |
| 540 } | |
| 541 } | |
| 542 { | |
| 543 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 544 impl_thread_and_main_thread_blocked(&proxy_); | |
| 545 resource_manager->ReduceMemory(resource_provider()); | |
| 546 } | |
| 547 EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); | |
| 548 | |
| 549 // Send the last two of the textures to a parent compositor. | |
| 550 ResourceProvider::ResourceIdArray to_send; | |
| 551 TransferableResourceArray transferable; | |
| 552 for (size_t i = 6; i < 8; ++i) | |
| 553 to_send.push_back(textures[i]->resource_id()); | |
| 554 resource_provider_->PrepareSendToParent(to_send, &transferable); | |
| 555 | |
| 556 // Set the last two textures to be tied for prioity with the two | |
| 557 // before them. Being sent to the parent will break the tie. | |
| 558 textures[4]->set_request_priority(100 + 4); | |
| 559 textures[5]->set_request_priority(100 + 5); | |
| 560 textures[6]->set_request_priority(100 + 4); | |
| 561 textures[7]->set_request_priority(100 + 5); | |
| 562 | |
| 563 for (size_t i = 0; i < 8; ++i) | |
| 564 texture_resource_ids[i] = textures[i]->resource_id(); | |
| 565 | |
| 566 // Drop all the textures. Now we have backings that can be recycled. | |
| 567 for (size_t i = 0; i < 8; ++i) | |
| 568 textures[0] = nullptr; | |
| 569 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 570 | |
| 571 // The next commit finishes. | |
| 572 { | |
| 573 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 574 impl_thread_and_main_thread_blocked(&proxy_); | |
| 575 resource_manager->UpdateBackingsState(resource_provider()); | |
| 576 } | |
| 577 | |
| 578 // Evict four textures. It would be the last four again, except that 2 of them | |
| 579 // are sent to the parent, so they are evicted last. | |
| 580 { | |
| 581 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 582 impl_thread_and_main_thread_blocked(&proxy_); | |
| 583 resource_manager->ReduceMemoryOnImplThread( | |
| 584 TexturesMemorySize(4), 200, resource_provider()); | |
| 585 | |
| 586 EXPECT_EQ(4u, EvictedBackingCount(resource_manager.get())); | |
| 587 // The last 2 backings remain this time. | |
| 588 std::vector<unsigned> remaining = BackingResources(resource_manager.get()); | |
| 589 EXPECT_TRUE(std::find(remaining.begin(), | |
| 590 remaining.end(), | |
| 591 texture_resource_ids[6]) == remaining.end()); | |
| 592 EXPECT_TRUE(std::find(remaining.begin(), | |
| 593 remaining.end(), | |
| 594 texture_resource_ids[7]) == remaining.end()); | |
| 595 } | |
| 596 resource_manager->UnlinkAndClearEvictedBackings(); | |
| 597 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryUseBytes()); | |
| 598 | |
| 599 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 600 impl_thread_and_main_thread_blocked(&proxy_); | |
| 601 resource_manager->ClearAllMemory(resource_provider()); | |
| 602 } | |
| 603 | |
| 604 TEST_F(PrioritizedResourceTest, ResourceManagerPartialUpdateTextures) { | |
| 605 const size_t kMaxTextures = 4; | |
| 606 const size_t kNumTextures = 4; | |
| 607 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 608 CreateManager(kMaxTextures); | |
| 609 scoped_ptr<PrioritizedResource> textures[kNumTextures]; | |
| 610 scoped_ptr<PrioritizedResource> more_textures[kNumTextures]; | |
| 611 | |
| 612 for (size_t i = 0; i < kNumTextures; ++i) { | |
| 613 textures[i] = | |
| 614 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 615 more_textures[i] = | |
| 616 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 617 } | |
| 618 | |
| 619 for (size_t i = 0; i < kNumTextures; ++i) | |
| 620 textures[i]->set_request_priority(200 + i); | |
| 621 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 622 | |
| 623 // Allocate textures which are currently high priority. | |
| 624 EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); | |
| 625 EXPECT_TRUE(ValidateTexture(textures[1].get(), false)); | |
| 626 EXPECT_TRUE(ValidateTexture(textures[2].get(), false)); | |
| 627 EXPECT_TRUE(ValidateTexture(textures[3].get(), false)); | |
| 628 | |
| 629 EXPECT_TRUE(textures[0]->have_backing_texture()); | |
| 630 EXPECT_TRUE(textures[1]->have_backing_texture()); | |
| 631 EXPECT_TRUE(textures[2]->have_backing_texture()); | |
| 632 EXPECT_TRUE(textures[3]->have_backing_texture()); | |
| 633 | |
| 634 for (size_t i = 0; i < kNumTextures; ++i) | |
| 635 more_textures[i]->set_request_priority(100 + i); | |
| 636 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 637 | |
| 638 // Textures are now below cutoff. | |
| 639 EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); | |
| 640 EXPECT_FALSE(ValidateTexture(textures[1].get(), false)); | |
| 641 EXPECT_FALSE(ValidateTexture(textures[2].get(), false)); | |
| 642 EXPECT_FALSE(ValidateTexture(textures[3].get(), false)); | |
| 643 | |
| 644 // But they are still valid to use. | |
| 645 EXPECT_TRUE(textures[0]->have_backing_texture()); | |
| 646 EXPECT_TRUE(textures[1]->have_backing_texture()); | |
| 647 EXPECT_TRUE(textures[2]->have_backing_texture()); | |
| 648 EXPECT_TRUE(textures[3]->have_backing_texture()); | |
| 649 | |
| 650 // Higher priority textures are finally needed. | |
| 651 EXPECT_TRUE(ValidateTexture(more_textures[0].get(), false)); | |
| 652 EXPECT_TRUE(ValidateTexture(more_textures[1].get(), false)); | |
| 653 EXPECT_TRUE(ValidateTexture(more_textures[2].get(), false)); | |
| 654 EXPECT_TRUE(ValidateTexture(more_textures[3].get(), false)); | |
| 655 | |
| 656 // Lower priority have been fully evicted. | |
| 657 EXPECT_FALSE(textures[0]->have_backing_texture()); | |
| 658 EXPECT_FALSE(textures[1]->have_backing_texture()); | |
| 659 EXPECT_FALSE(textures[2]->have_backing_texture()); | |
| 660 EXPECT_FALSE(textures[3]->have_backing_texture()); | |
| 661 | |
| 662 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 663 impl_thread_and_main_thread_blocked(&proxy_); | |
| 664 resource_manager->ClearAllMemory(resource_provider()); | |
| 665 } | |
| 666 | |
| 667 TEST_F(PrioritizedResourceTest, ResourceManagerPrioritiesAreEqual) { | |
| 668 const size_t kMaxTextures = 16; | |
| 669 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 670 CreateManager(kMaxTextures); | |
| 671 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 672 | |
| 673 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 674 textures[i] = | |
| 675 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 676 } | |
| 677 | |
| 678 // All 16 textures have the same priority except 2 higher priority. | |
| 679 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 680 textures[i]->set_request_priority(100); | |
| 681 textures[0]->set_request_priority(99); | |
| 682 textures[1]->set_request_priority(99); | |
| 683 | |
| 684 // Set max limit to 8 textures | |
| 685 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); | |
| 686 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 687 | |
| 688 // The two high priority textures should be available, others should not. | |
| 689 for (size_t i = 0; i < 2; ++i) | |
| 690 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); | |
| 691 for (size_t i = 2; i < kMaxTextures; ++i) | |
| 692 EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); | |
| 693 EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryAboveCutoffBytes()); | |
| 694 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 695 resource_manager->MemoryAboveCutoffBytes()); | |
| 696 | |
| 697 // Manually reserving textures should only succeed on the higher priority | |
| 698 // textures, and on remaining textures up to the memory limit. | |
| 699 for (size_t i = 0; i < 8; i++) | |
| 700 EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); | |
| 701 for (size_t i = 9; i < kMaxTextures; i++) | |
| 702 EXPECT_FALSE(ValidateTexture(textures[i].get(), true)); | |
| 703 EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); | |
| 704 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 705 resource_manager->MemoryAboveCutoffBytes()); | |
| 706 | |
| 707 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 708 impl_thread_and_main_thread_blocked(&proxy_); | |
| 709 resource_manager->ClearAllMemory(resource_provider()); | |
| 710 } | |
| 711 | |
| 712 TEST_F(PrioritizedResourceTest, ResourceManagerDestroyedFirst) { | |
| 713 scoped_ptr<PrioritizedResourceManager> resource_manager = CreateManager(1); | |
| 714 scoped_ptr<PrioritizedResource> texture = | |
| 715 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 716 | |
| 717 // Texture is initially invalid, but it will become available. | |
| 718 EXPECT_FALSE(texture->have_backing_texture()); | |
| 719 | |
| 720 texture->set_request_priority(100); | |
| 721 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 722 | |
| 723 EXPECT_TRUE(ValidateTexture(texture.get(), false)); | |
| 724 EXPECT_TRUE(texture->can_acquire_backing_texture()); | |
| 725 EXPECT_TRUE(texture->have_backing_texture()); | |
| 726 { | |
| 727 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 728 impl_thread_and_main_thread_blocked(&proxy_); | |
| 729 resource_manager->ClearAllMemory(resource_provider()); | |
| 730 } | |
| 731 resource_manager = nullptr; | |
| 732 | |
| 733 EXPECT_FALSE(texture->can_acquire_backing_texture()); | |
| 734 EXPECT_FALSE(texture->have_backing_texture()); | |
| 735 } | |
| 736 | |
| 737 TEST_F(PrioritizedResourceTest, TextureMovedToNewManager) { | |
| 738 scoped_ptr<PrioritizedResourceManager> resource_manager_one = | |
| 739 CreateManager(1); | |
| 740 scoped_ptr<PrioritizedResourceManager> resource_manager_two = | |
| 741 CreateManager(1); | |
| 742 scoped_ptr<PrioritizedResource> texture = | |
| 743 resource_manager_one->CreateTexture(texture_size_, texture_format_); | |
| 744 | |
| 745 // Texture is initially invalid, but it will become available. | |
| 746 EXPECT_FALSE(texture->have_backing_texture()); | |
| 747 | |
| 748 texture->set_request_priority(100); | |
| 749 PrioritizeTexturesAndBackings(resource_manager_one.get()); | |
| 750 | |
| 751 EXPECT_TRUE(ValidateTexture(texture.get(), false)); | |
| 752 EXPECT_TRUE(texture->can_acquire_backing_texture()); | |
| 753 EXPECT_TRUE(texture->have_backing_texture()); | |
| 754 | |
| 755 texture->SetTextureManager(NULL); | |
| 756 { | |
| 757 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 758 impl_thread_and_main_thread_blocked(&proxy_); | |
| 759 resource_manager_one->ClearAllMemory(resource_provider()); | |
| 760 } | |
| 761 resource_manager_one = nullptr; | |
| 762 | |
| 763 EXPECT_FALSE(texture->can_acquire_backing_texture()); | |
| 764 EXPECT_FALSE(texture->have_backing_texture()); | |
| 765 | |
| 766 texture->SetTextureManager(resource_manager_two.get()); | |
| 767 | |
| 768 PrioritizeTexturesAndBackings(resource_manager_two.get()); | |
| 769 | |
| 770 EXPECT_TRUE(ValidateTexture(texture.get(), false)); | |
| 771 EXPECT_TRUE(texture->can_acquire_backing_texture()); | |
| 772 EXPECT_TRUE(texture->have_backing_texture()); | |
| 773 | |
| 774 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 775 impl_thread_and_main_thread_blocked(&proxy_); | |
| 776 resource_manager_two->ClearAllMemory(resource_provider()); | |
| 777 } | |
| 778 | |
| 779 TEST_F(PrioritizedResourceTest, | |
| 780 RenderSurfacesReduceMemoryAvailableOutsideRootSurface) { | |
| 781 const size_t kMaxTextures = 8; | |
| 782 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 783 CreateManager(kMaxTextures); | |
| 784 | |
| 785 // Half of the memory is taken by surfaces (with high priority place-holder) | |
| 786 scoped_ptr<PrioritizedResource> render_surface_place_holder = | |
| 787 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 788 render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( | |
| 789 TexturesMemorySize(4)); | |
| 790 render_surface_place_holder->set_request_priority( | |
| 791 PriorityCalculator::RenderSurfacePriority()); | |
| 792 | |
| 793 // Create textures to fill our memory limit. | |
| 794 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 795 | |
| 796 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 797 textures[i] = | |
| 798 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 799 } | |
| 800 | |
| 801 // Set decreasing non-visible priorities outside root surface. | |
| 802 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 803 textures[i]->set_request_priority(100 + i); | |
| 804 | |
| 805 // Only lower half should be available. | |
| 806 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 807 EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); | |
| 808 EXPECT_TRUE(ValidateTexture(textures[3].get(), false)); | |
| 809 EXPECT_FALSE(ValidateTexture(textures[4].get(), false)); | |
| 810 EXPECT_FALSE(ValidateTexture(textures[7].get(), false)); | |
| 811 | |
| 812 // Set increasing non-visible priorities outside root surface. | |
| 813 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 814 textures[i]->set_request_priority(100 - i); | |
| 815 | |
| 816 // Only upper half should be available. | |
| 817 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 818 EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); | |
| 819 EXPECT_FALSE(ValidateTexture(textures[3].get(), false)); | |
| 820 EXPECT_TRUE(ValidateTexture(textures[4].get(), false)); | |
| 821 EXPECT_TRUE(ValidateTexture(textures[7].get(), false)); | |
| 822 | |
| 823 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); | |
| 824 EXPECT_EQ(TexturesMemorySize(4), | |
| 825 resource_manager->MemoryForSelfManagedTextures()); | |
| 826 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 827 resource_manager->MemoryAboveCutoffBytes()); | |
| 828 EXPECT_EQ(TexturesMemorySize(8), | |
| 829 resource_manager->MaxMemoryNeededBytes()); | |
| 830 | |
| 831 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 832 impl_thread_and_main_thread_blocked(&proxy_); | |
| 833 resource_manager->ClearAllMemory(resource_provider()); | |
| 834 } | |
| 835 | |
| 836 TEST_F(PrioritizedResourceTest, | |
| 837 RenderSurfacesReduceMemoryAvailableForRequestLate) { | |
| 838 const size_t kMaxTextures = 8; | |
| 839 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 840 CreateManager(kMaxTextures); | |
| 841 | |
| 842 // Half of the memory is taken by surfaces (with high priority place-holder) | |
| 843 scoped_ptr<PrioritizedResource> render_surface_place_holder = | |
| 844 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 845 render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( | |
| 846 TexturesMemorySize(4)); | |
| 847 render_surface_place_holder->set_request_priority( | |
| 848 PriorityCalculator::RenderSurfacePriority()); | |
| 849 | |
| 850 // Create textures to fill our memory limit. | |
| 851 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 852 | |
| 853 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 854 textures[i] = | |
| 855 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 856 } | |
| 857 | |
| 858 // Set equal priorities. | |
| 859 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 860 textures[i]->set_request_priority(100); | |
| 861 | |
| 862 // The first four to be requested late will be available. | |
| 863 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 864 for (unsigned i = 0; i < kMaxTextures; ++i) | |
| 865 EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); | |
| 866 for (unsigned i = 0; i < kMaxTextures; i += 2) | |
| 867 EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); | |
| 868 for (unsigned i = 1; i < kMaxTextures; i += 2) | |
| 869 EXPECT_FALSE(ValidateTexture(textures[i].get(), true)); | |
| 870 | |
| 871 EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); | |
| 872 EXPECT_EQ(TexturesMemorySize(4), | |
| 873 resource_manager->MemoryForSelfManagedTextures()); | |
| 874 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 875 resource_manager->MemoryAboveCutoffBytes()); | |
| 876 EXPECT_EQ(TexturesMemorySize(8), | |
| 877 resource_manager->MaxMemoryNeededBytes()); | |
| 878 | |
| 879 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 880 impl_thread_and_main_thread_blocked(&proxy_); | |
| 881 resource_manager->ClearAllMemory(resource_provider()); | |
| 882 } | |
| 883 | |
| 884 TEST_F(PrioritizedResourceTest, | |
| 885 WhenRenderSurfaceNotAvailableTexturesAlsoNotAvailable) { | |
| 886 const size_t kMaxTextures = 8; | |
| 887 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 888 CreateManager(kMaxTextures); | |
| 889 | |
| 890 // Half of the memory is taken by surfaces (with high priority place-holder) | |
| 891 scoped_ptr<PrioritizedResource> render_surface_place_holder = | |
| 892 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 893 render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( | |
| 894 TexturesMemorySize(4)); | |
| 895 render_surface_place_holder->set_request_priority( | |
| 896 PriorityCalculator::RenderSurfacePriority()); | |
| 897 | |
| 898 // Create textures to fill our memory limit. | |
| 899 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 900 | |
| 901 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 902 textures[i] = | |
| 903 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 904 | |
| 905 // Set 6 visible textures in the root surface, and 2 in a child surface. | |
| 906 for (size_t i = 0; i < 6; ++i) { | |
| 907 textures[i]-> | |
| 908 set_request_priority(PriorityCalculator::VisiblePriority(true)); | |
| 909 } | |
| 910 for (size_t i = 6; i < 8; ++i) { | |
| 911 textures[i]-> | |
| 912 set_request_priority(PriorityCalculator::VisiblePriority(false)); | |
| 913 } | |
| 914 | |
| 915 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 916 | |
| 917 // Unable to request_late textures in the child surface. | |
| 918 EXPECT_FALSE(ValidateTexture(textures[6].get(), true)); | |
| 919 EXPECT_FALSE(ValidateTexture(textures[7].get(), true)); | |
| 920 | |
| 921 // Root surface textures are valid. | |
| 922 for (size_t i = 0; i < 6; ++i) | |
| 923 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); | |
| 924 | |
| 925 EXPECT_EQ(TexturesMemorySize(6), resource_manager->MemoryAboveCutoffBytes()); | |
| 926 EXPECT_EQ(TexturesMemorySize(2), | |
| 927 resource_manager->MemoryForSelfManagedTextures()); | |
| 928 EXPECT_LE(resource_manager->MemoryUseBytes(), | |
| 929 resource_manager->MemoryAboveCutoffBytes()); | |
| 930 | |
| 931 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 932 impl_thread_and_main_thread_blocked(&proxy_); | |
| 933 resource_manager->ClearAllMemory(resource_provider()); | |
| 934 } | |
| 935 | |
| 936 TEST_F(PrioritizedResourceTest, RequestLateBackingsSorting) { | |
| 937 const size_t kMaxTextures = 8; | |
| 938 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 939 CreateManager(kMaxTextures); | |
| 940 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); | |
| 941 | |
| 942 // Create textures to fill our memory limit. | |
| 943 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 944 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 945 textures[i] = | |
| 946 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 947 | |
| 948 // Set equal priorities, and allocate backings for all textures. | |
| 949 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 950 textures[i]->set_request_priority(100); | |
| 951 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 952 for (unsigned i = 0; i < kMaxTextures; ++i) | |
| 953 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); | |
| 954 | |
| 955 // Drop the memory limit and prioritize (none will be above the threshold, | |
| 956 // but they still have backings because ReduceMemory hasn't been called). | |
| 957 resource_manager->SetMaxMemoryLimitBytes( | |
| 958 TexturesMemorySize(kMaxTextures / 2)); | |
| 959 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 960 | |
| 961 // Push half of them back over the limit. | |
| 962 for (size_t i = 0; i < kMaxTextures; i += 2) | |
| 963 EXPECT_TRUE(textures[i]->RequestLate()); | |
| 964 | |
| 965 // Push the priorities to the backings array and sort the backings array | |
| 966 ResourceManagerUpdateBackingsPriorities(resource_manager.get()); | |
| 967 | |
| 968 // Assert that the backings list be sorted with the below-limit backings | |
| 969 // before the above-limit backings. | |
| 970 ResourceManagerAssertInvariants(resource_manager.get()); | |
| 971 | |
| 972 // Make sure that we have backings for all of the textures. | |
| 973 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 974 EXPECT_TRUE(textures[i]->have_backing_texture()); | |
| 975 | |
| 976 // Make sure that only the request_late textures are above the priority | |
| 977 // cutoff | |
| 978 for (size_t i = 0; i < kMaxTextures; i += 2) | |
| 979 EXPECT_TRUE(TextureBackingIsAbovePriorityCutoff(textures[i].get())); | |
| 980 for (size_t i = 1; i < kMaxTextures; i += 2) | |
| 981 EXPECT_FALSE(TextureBackingIsAbovePriorityCutoff(textures[i].get())); | |
| 982 | |
| 983 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 984 impl_thread_and_main_thread_blocked(&proxy_); | |
| 985 resource_manager->ClearAllMemory(resource_provider()); | |
| 986 } | |
| 987 | |
| 988 TEST_F(PrioritizedResourceTest, ClearUploadsToEvictedResources) { | |
| 989 const size_t kMaxTextures = 4; | |
| 990 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 991 CreateManager(kMaxTextures); | |
| 992 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); | |
| 993 | |
| 994 // Create textures to fill our memory limit. | |
| 995 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 996 | |
| 997 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 998 textures[i] = | |
| 999 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 1000 | |
| 1001 // Set equal priorities, and allocate backings for all textures. | |
| 1002 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 1003 textures[i]->set_request_priority(100); | |
| 1004 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 1005 for (unsigned i = 0; i < kMaxTextures; ++i) | |
| 1006 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); | |
| 1007 | |
| 1008 ResourceUpdateQueue queue; | |
| 1009 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 1010 impl_thread_and_main_thread_blocked(&proxy_); | |
| 1011 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 1012 const ResourceUpdate upload = ResourceUpdate::Create( | |
| 1013 textures[i].get(), NULL, gfx::Rect(), gfx::Rect(), gfx::Vector2d()); | |
| 1014 queue.AppendFullUpload(upload); | |
| 1015 } | |
| 1016 | |
| 1017 // Make sure that we have backings for all of the textures. | |
| 1018 for (size_t i = 0; i < kMaxTextures; ++i) | |
| 1019 EXPECT_TRUE(textures[i]->have_backing_texture()); | |
| 1020 | |
| 1021 queue.ClearUploadsToEvictedResources(); | |
| 1022 EXPECT_EQ(4u, queue.FullUploadSize()); | |
| 1023 | |
| 1024 resource_manager->ReduceMemoryOnImplThread( | |
| 1025 TexturesMemorySize(1), | |
| 1026 PriorityCalculator::AllowEverythingCutoff(), | |
| 1027 resource_provider()); | |
| 1028 queue.ClearUploadsToEvictedResources(); | |
| 1029 EXPECT_EQ(1u, queue.FullUploadSize()); | |
| 1030 | |
| 1031 resource_manager->ReduceMemoryOnImplThread( | |
| 1032 0, PriorityCalculator::AllowEverythingCutoff(), resource_provider()); | |
| 1033 queue.ClearUploadsToEvictedResources(); | |
| 1034 EXPECT_EQ(0u, queue.FullUploadSize()); | |
| 1035 } | |
| 1036 | |
| 1037 TEST_F(PrioritizedResourceTest, UsageStatistics) { | |
| 1038 const size_t kMaxTextures = 5; | |
| 1039 scoped_ptr<PrioritizedResourceManager> resource_manager = | |
| 1040 CreateManager(kMaxTextures); | |
| 1041 scoped_ptr<PrioritizedResource> textures[kMaxTextures]; | |
| 1042 | |
| 1043 for (size_t i = 0; i < kMaxTextures; ++i) { | |
| 1044 textures[i] = | |
| 1045 resource_manager->CreateTexture(texture_size_, texture_format_); | |
| 1046 } | |
| 1047 | |
| 1048 textures[0]-> | |
| 1049 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); | |
| 1050 textures[1]-> | |
| 1051 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff()); | |
| 1052 textures[2]->set_request_priority( | |
| 1053 PriorityCalculator::AllowVisibleAndNearbyCutoff() - 1); | |
| 1054 textures[3]-> | |
| 1055 set_request_priority(PriorityCalculator::AllowVisibleAndNearbyCutoff()); | |
| 1056 textures[4]->set_request_priority( | |
| 1057 PriorityCalculator::AllowVisibleAndNearbyCutoff() + 1); | |
| 1058 | |
| 1059 // Set max limit to 2 textures. | |
| 1060 resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(2)); | |
| 1061 PrioritizeTexturesAndBackings(resource_manager.get()); | |
| 1062 | |
| 1063 // The first two textures should be available, others should not. | |
| 1064 for (size_t i = 0; i < 2; ++i) | |
| 1065 EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); | |
| 1066 for (size_t i = 2; i < kMaxTextures; ++i) | |
| 1067 EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); | |
| 1068 | |
| 1069 // Validate the statistics. | |
| 1070 { | |
| 1071 DebugScopedSetImplThread impl_thread(&proxy_); | |
| 1072 EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); | |
| 1073 EXPECT_EQ(TexturesMemorySize(1), resource_manager->MemoryVisibleBytes()); | |
| 1074 EXPECT_EQ(TexturesMemorySize(3), | |
| 1075 resource_manager->MemoryVisibleAndNearbyBytes()); | |
| 1076 } | |
| 1077 | |
| 1078 // Re-prioritize the textures, but do not push the values to backings. | |
| 1079 textures[0]-> | |
| 1080 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); | |
| 1081 textures[1]-> | |
| 1082 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); | |
| 1083 textures[2]-> | |
| 1084 set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); | |
| 1085 textures[3]->set_request_priority( | |
| 1086 PriorityCalculator::AllowVisibleAndNearbyCutoff() - 1); | |
| 1087 textures[4]-> | |
| 1088 set_request_priority(PriorityCalculator::AllowVisibleAndNearbyCutoff()); | |
| 1089 resource_manager->PrioritizeTextures(); | |
| 1090 | |
| 1091 // Verify that we still see the old values. | |
| 1092 { | |
| 1093 DebugScopedSetImplThread impl_thread(&proxy_); | |
| 1094 EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); | |
| 1095 EXPECT_EQ(TexturesMemorySize(1), resource_manager->MemoryVisibleBytes()); | |
| 1096 EXPECT_EQ(TexturesMemorySize(3), | |
| 1097 resource_manager->MemoryVisibleAndNearbyBytes()); | |
| 1098 } | |
| 1099 | |
| 1100 // Push priorities to backings, and verify we see the new values. | |
| 1101 { | |
| 1102 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 1103 impl_thread_and_main_thread_blocked(&proxy_); | |
| 1104 resource_manager->PushTexturePrioritiesToBackings(); | |
| 1105 EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); | |
| 1106 EXPECT_EQ(TexturesMemorySize(3), resource_manager->MemoryVisibleBytes()); | |
| 1107 EXPECT_EQ(TexturesMemorySize(4), | |
| 1108 resource_manager->MemoryVisibleAndNearbyBytes()); | |
| 1109 } | |
| 1110 | |
| 1111 DebugScopedSetImplThreadAndMainThreadBlocked | |
| 1112 impl_thread_and_main_thread_blocked(&proxy_); | |
| 1113 resource_manager->ClearAllMemory(resource_provider()); | |
| 1114 } | |
| 1115 | |
| 1116 } // namespace | |
| 1117 } // namespace cc | |
| OLD | NEW |