| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/resources/prioritized_resource.h" |
| |
| #include <vector> |
| |
| #include "cc/resources/prioritized_resource_manager.h" |
| #include "cc/resources/resource.h" |
| #include "cc/resources/resource_provider.h" |
| #include "cc/test/fake_output_surface.h" |
| #include "cc/test/fake_output_surface_client.h" |
| #include "cc/test/fake_proxy.h" |
| #include "cc/test/test_shared_bitmap_manager.h" |
| #include "cc/test/tiled_layer_test_common.h" |
| #include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace cc { |
| |
| class PrioritizedResourceTest : public testing::Test { |
| public: |
| PrioritizedResourceTest() |
| : texture_size_(256, 256), |
| texture_format_(RGBA_8888), |
| output_surface_(FakeOutputSurface::Create3d()) { |
| DebugScopedSetImplThread impl_thread(&proxy_); |
| CHECK(output_surface_->BindToClient(&output_surface_client_)); |
| shared_bitmap_manager_.reset(new TestSharedBitmapManager()); |
| resource_provider_ = ResourceProvider::Create(output_surface_.get(), |
| shared_bitmap_manager_.get(), |
| NULL, |
| 0, |
| false, |
| 1, |
| false); |
| } |
| |
| virtual ~PrioritizedResourceTest() { |
| DebugScopedSetImplThread impl_thread(&proxy_); |
| resource_provider_ = nullptr; |
| } |
| |
| size_t TexturesMemorySize(size_t texture_count) { |
| return Resource::MemorySizeBytes(texture_size_, texture_format_) * |
| texture_count; |
| } |
| |
| scoped_ptr<PrioritizedResourceManager> CreateManager(size_t max_textures) { |
| scoped_ptr<PrioritizedResourceManager> manager = |
| PrioritizedResourceManager::Create(&proxy_); |
| manager->SetMaxMemoryLimitBytes(TexturesMemorySize(max_textures)); |
| return manager.Pass(); |
| } |
| |
| bool ValidateTexture(PrioritizedResource* texture, |
| bool request_late) { |
| ResourceManagerAssertInvariants(texture->resource_manager()); |
| if (request_late) |
| texture->RequestLate(); |
| ResourceManagerAssertInvariants(texture->resource_manager()); |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| bool success = texture->can_acquire_backing_texture(); |
| if (success) |
| texture->AcquireBackingTexture(resource_provider()); |
| return success; |
| } |
| |
| void PrioritizeTexturesAndBackings( |
| PrioritizedResourceManager* resource_manager) { |
| resource_manager->PrioritizeTextures(); |
| ResourceManagerUpdateBackingsPriorities(resource_manager); |
| } |
| |
| void ResourceManagerUpdateBackingsPriorities( |
| PrioritizedResourceManager* resource_manager) { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->PushTexturePrioritiesToBackings(); |
| } |
| |
| ResourceProvider* resource_provider() { return resource_provider_.get(); } |
| |
| void ResourceManagerAssertInvariants( |
| PrioritizedResourceManager* resource_manager) { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->AssertInvariants(); |
| } |
| |
| bool TextureBackingIsAbovePriorityCutoff(PrioritizedResource* texture) { |
| return texture->backing()-> |
| was_above_priority_cutoff_at_last_priority_update(); |
| } |
| |
| size_t EvictedBackingCount(PrioritizedResourceManager* resource_manager) { |
| return resource_manager->evicted_backings_.size(); |
| } |
| |
| std::vector<unsigned> BackingResources( |
| PrioritizedResourceManager* resource_manager) { |
| std::vector<unsigned> resources; |
| for (PrioritizedResourceManager::BackingList::iterator it = |
| resource_manager->backings_.begin(); |
| it != resource_manager->backings_.end(); |
| ++it) |
| resources.push_back((*it)->id()); |
| return resources; |
| } |
| |
| protected: |
| FakeProxy proxy_; |
| const gfx::Size texture_size_; |
| const ResourceFormat texture_format_; |
| FakeOutputSurfaceClient output_surface_client_; |
| scoped_ptr<OutputSurface> output_surface_; |
| scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; |
| scoped_ptr<ResourceProvider> resource_provider_; |
| }; |
| |
| namespace { |
| |
| TEST_F(PrioritizedResourceTest, RequestTextureExceedingMaxLimit) { |
| const size_t kMaxTextures = 8; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| |
| // Create textures for double our memory limit. |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures * 2]; |
| |
| for (size_t i = 0; i < kMaxTextures * 2; ++i) |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| |
| // Set decreasing priorities |
| for (size_t i = 0; i < kMaxTextures * 2; ++i) |
| textures[i]->set_request_priority(100 + i); |
| |
| // Only lower half should be available. |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[7].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[8].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[15].get(), false)); |
| |
| // Set increasing priorities |
| for (size_t i = 0; i < kMaxTextures * 2; ++i) |
| textures[i]->set_request_priority(100 - i); |
| |
| // Only upper half should be available. |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[7].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[8].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[15].get(), false)); |
| |
| EXPECT_EQ(TexturesMemorySize(kMaxTextures), |
| resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_EQ(TexturesMemorySize(2*kMaxTextures), |
| resource_manager->MaxMemoryNeededBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, ChangeMemoryLimits) { |
| const size_t kMaxTextures = 8; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100 + i); |
| |
| // Set max limit to 8 textures |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| ValidateTexture(textures[i].get(), false); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| |
| EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| |
| // Set max limit to 5 textures |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(5)); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 5); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| |
| EXPECT_EQ(TexturesMemorySize(5), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_EQ(TexturesMemorySize(kMaxTextures), |
| resource_manager->MaxMemoryNeededBytes()); |
| |
| // Set max limit to 4 textures |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(4)); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| |
| EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_EQ(TexturesMemorySize(kMaxTextures), |
| resource_manager->MaxMemoryNeededBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, ReduceWastedMemory) { |
| const size_t kMaxTextures = 20; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100 + i); |
| |
| // Set the memory limit to the max number of textures. |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // Create backings and textures for all of the textures. |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| ValidateTexture(textures[i].get(), false); |
| |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| uint8_t image[4] = {0}; |
| textures[i]->SetPixels(resource_provider_.get(), |
| image, |
| gfx::Rect(1, 1), |
| gfx::Rect(1, 1), |
| gfx::Vector2d()); |
| } |
| } |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| |
| // 20 textures have backings allocated. |
| EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); |
| |
| // Destroy one texture, not enough is wasted to cause cleanup. |
| textures[0] = nullptr; |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->UpdateBackingsState(resource_provider()); |
| resource_manager->ReduceWastedMemory(resource_provider()); |
| } |
| EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); |
| |
| // Destroy half the textures, leaving behind the backings. Now a cleanup |
| // should happen. |
| for (size_t i = 0; i < kMaxTextures / 2; ++i) |
| textures[i] = nullptr; |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->UpdateBackingsState(resource_provider()); |
| resource_manager->ReduceWastedMemory(resource_provider()); |
| } |
| EXPECT_GT(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, InUseNotWastedMemory) { |
| const size_t kMaxTextures = 20; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100 + i); |
| |
| // Set the memory limit to the max number of textures. |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // Create backings and textures for all of the textures. |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| ValidateTexture(textures[i].get(), false); |
| |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| uint8_t image[4] = {0}; |
| textures[i]->SetPixels(resource_provider_.get(), |
| image, |
| gfx::Rect(1, 1), |
| gfx::Rect(1, 1), |
| gfx::Vector2d()); |
| } |
| } |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| |
| // 20 textures have backings allocated. |
| EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); |
| |
| // Send half the textures to a parent compositor. |
| ResourceProvider::ResourceIdArray to_send; |
| TransferableResourceArray transferable; |
| for (size_t i = 0; i < kMaxTextures / 2; ++i) |
| to_send.push_back(textures[i]->resource_id()); |
| resource_provider_->PrepareSendToParent(to_send, &transferable); |
| |
| // Destroy half the textures, leaving behind the backings. The backings are |
| // sent to a parent compositor though, so they should not be considered wasted |
| // and a cleanup should not happen. |
| for (size_t i = 0; i < kMaxTextures / 2; ++i) |
| textures[i] = nullptr; |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->UpdateBackingsState(resource_provider()); |
| resource_manager->ReduceWastedMemory(resource_provider()); |
| } |
| EXPECT_EQ(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); |
| |
| // Receive the textures back from the parent compositor. Now a cleanup should |
| // happen. |
| ReturnedResourceArray returns; |
| TransferableResource::ReturnResources(transferable, &returns); |
| resource_provider_->ReceiveReturnsFromParent(returns); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->UpdateBackingsState(resource_provider()); |
| resource_manager->ReduceWastedMemory(resource_provider()); |
| } |
| EXPECT_GT(TexturesMemorySize(20), resource_manager->MemoryUseBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, ChangePriorityCutoff) { |
| const size_t kMaxTextures = 8; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100 + i); |
| |
| // Set the cutoff to drop two textures. Try to request_late on all textures, |
| // and make sure that request_late doesn't work on a texture with equal |
| // priority to the cutoff. |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); |
| resource_manager->SetExternalPriorityCutoff(106); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| EXPECT_EQ(ValidateTexture(textures[i].get(), true), i < 6); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| EXPECT_EQ(TexturesMemorySize(6), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| |
| // Set the cutoff to drop two more textures. |
| resource_manager->SetExternalPriorityCutoff(104); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); |
| |
| // Do a one-time eviction for one more texture based on priority cutoff |
| resource_manager->UnlinkAndClearEvictedBackings(); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemoryOnImplThread( |
| TexturesMemorySize(8), 104, resource_provider()); |
| EXPECT_EQ(0u, EvictedBackingCount(resource_manager.get())); |
| resource_manager->ReduceMemoryOnImplThread( |
| TexturesMemorySize(8), 103, resource_provider()); |
| EXPECT_EQ(1u, EvictedBackingCount(resource_manager.get())); |
| } |
| resource_manager->UnlinkAndClearEvictedBackings(); |
| EXPECT_EQ(TexturesMemorySize(3), resource_manager->MemoryUseBytes()); |
| |
| // Re-allocate the the texture after the one-time drop. |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| EXPECT_EQ(ValidateTexture(textures[i].get(), false), i < 4); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, EvictingTexturesInParent) { |
| const size_t kMaxTextures = 8; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| unsigned texture_resource_ids[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| textures[i]->set_request_priority(100 + i); |
| } |
| |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); |
| |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| uint8_t image[4] = {0}; |
| textures[i]->SetPixels(resource_provider_.get(), |
| image, |
| gfx::Rect(1, 1), |
| gfx::Rect(1, 1), |
| gfx::Vector2d()); |
| } |
| } |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); |
| |
| for (size_t i = 0; i < 8; ++i) |
| texture_resource_ids[i] = textures[i]->resource_id(); |
| |
| // Evict four textures. It will be the last four. |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemoryOnImplThread( |
| TexturesMemorySize(4), 200, resource_provider()); |
| |
| EXPECT_EQ(4u, EvictedBackingCount(resource_manager.get())); |
| |
| // The last four backings are evicted. |
| std::vector<unsigned> remaining = BackingResources(resource_manager.get()); |
| EXPECT_TRUE(std::find(remaining.begin(), |
| remaining.end(), |
| texture_resource_ids[0]) != remaining.end()); |
| EXPECT_TRUE(std::find(remaining.begin(), |
| remaining.end(), |
| texture_resource_ids[1]) != remaining.end()); |
| EXPECT_TRUE(std::find(remaining.begin(), |
| remaining.end(), |
| texture_resource_ids[2]) != remaining.end()); |
| EXPECT_TRUE(std::find(remaining.begin(), |
| remaining.end(), |
| texture_resource_ids[3]) != remaining.end()); |
| } |
| resource_manager->UnlinkAndClearEvictedBackings(); |
| EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryUseBytes()); |
| |
| // Re-allocate the the texture after the eviction. |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); |
| |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| uint8_t image[4] = {0}; |
| textures[i]->SetPixels(resource_provider_.get(), |
| image, |
| gfx::Rect(1, 1), |
| gfx::Rect(1, 1), |
| gfx::Vector2d()); |
| } |
| } |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemory(resource_provider()); |
| } |
| EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); |
| |
| // Send the last two of the textures to a parent compositor. |
| ResourceProvider::ResourceIdArray to_send; |
| TransferableResourceArray transferable; |
| for (size_t i = 6; i < 8; ++i) |
| to_send.push_back(textures[i]->resource_id()); |
| resource_provider_->PrepareSendToParent(to_send, &transferable); |
| |
| // Set the last two textures to be tied for prioity with the two |
| // before them. Being sent to the parent will break the tie. |
| textures[4]->set_request_priority(100 + 4); |
| textures[5]->set_request_priority(100 + 5); |
| textures[6]->set_request_priority(100 + 4); |
| textures[7]->set_request_priority(100 + 5); |
| |
| for (size_t i = 0; i < 8; ++i) |
| texture_resource_ids[i] = textures[i]->resource_id(); |
| |
| // Drop all the textures. Now we have backings that can be recycled. |
| for (size_t i = 0; i < 8; ++i) |
| textures[0] = nullptr; |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // The next commit finishes. |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->UpdateBackingsState(resource_provider()); |
| } |
| |
| // Evict four textures. It would be the last four again, except that 2 of them |
| // are sent to the parent, so they are evicted last. |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ReduceMemoryOnImplThread( |
| TexturesMemorySize(4), 200, resource_provider()); |
| |
| EXPECT_EQ(4u, EvictedBackingCount(resource_manager.get())); |
| // The last 2 backings remain this time. |
| std::vector<unsigned> remaining = BackingResources(resource_manager.get()); |
| EXPECT_TRUE(std::find(remaining.begin(), |
| remaining.end(), |
| texture_resource_ids[6]) == remaining.end()); |
| EXPECT_TRUE(std::find(remaining.begin(), |
| remaining.end(), |
| texture_resource_ids[7]) == remaining.end()); |
| } |
| resource_manager->UnlinkAndClearEvictedBackings(); |
| EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryUseBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, ResourceManagerPartialUpdateTextures) { |
| const size_t kMaxTextures = 4; |
| const size_t kNumTextures = 4; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| scoped_ptr<PrioritizedResource> textures[kNumTextures]; |
| scoped_ptr<PrioritizedResource> more_textures[kNumTextures]; |
| |
| for (size_t i = 0; i < kNumTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| more_textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| |
| for (size_t i = 0; i < kNumTextures; ++i) |
| textures[i]->set_request_priority(200 + i); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // Allocate textures which are currently high priority. |
| EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[1].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[2].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[3].get(), false)); |
| |
| EXPECT_TRUE(textures[0]->have_backing_texture()); |
| EXPECT_TRUE(textures[1]->have_backing_texture()); |
| EXPECT_TRUE(textures[2]->have_backing_texture()); |
| EXPECT_TRUE(textures[3]->have_backing_texture()); |
| |
| for (size_t i = 0; i < kNumTextures; ++i) |
| more_textures[i]->set_request_priority(100 + i); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // Textures are now below cutoff. |
| EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[1].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[2].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[3].get(), false)); |
| |
| // But they are still valid to use. |
| EXPECT_TRUE(textures[0]->have_backing_texture()); |
| EXPECT_TRUE(textures[1]->have_backing_texture()); |
| EXPECT_TRUE(textures[2]->have_backing_texture()); |
| EXPECT_TRUE(textures[3]->have_backing_texture()); |
| |
| // Higher priority textures are finally needed. |
| EXPECT_TRUE(ValidateTexture(more_textures[0].get(), false)); |
| EXPECT_TRUE(ValidateTexture(more_textures[1].get(), false)); |
| EXPECT_TRUE(ValidateTexture(more_textures[2].get(), false)); |
| EXPECT_TRUE(ValidateTexture(more_textures[3].get(), false)); |
| |
| // Lower priority have been fully evicted. |
| EXPECT_FALSE(textures[0]->have_backing_texture()); |
| EXPECT_FALSE(textures[1]->have_backing_texture()); |
| EXPECT_FALSE(textures[2]->have_backing_texture()); |
| EXPECT_FALSE(textures[3]->have_backing_texture()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, ResourceManagerPrioritiesAreEqual) { |
| const size_t kMaxTextures = 16; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| |
| // All 16 textures have the same priority except 2 higher priority. |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100); |
| textures[0]->set_request_priority(99); |
| textures[1]->set_request_priority(99); |
| |
| // Set max limit to 8 textures |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(8)); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // The two high priority textures should be available, others should not. |
| for (size_t i = 0; i < 2; ++i) |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); |
| for (size_t i = 2; i < kMaxTextures; ++i) |
| EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); |
| EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| |
| // Manually reserving textures should only succeed on the higher priority |
| // textures, and on remaining textures up to the memory limit. |
| for (size_t i = 0; i < 8; i++) |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); |
| for (size_t i = 9; i < kMaxTextures; i++) |
| EXPECT_FALSE(ValidateTexture(textures[i].get(), true)); |
| EXPECT_EQ(TexturesMemorySize(8), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, ResourceManagerDestroyedFirst) { |
| scoped_ptr<PrioritizedResourceManager> resource_manager = CreateManager(1); |
| scoped_ptr<PrioritizedResource> texture = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| |
| // Texture is initially invalid, but it will become available. |
| EXPECT_FALSE(texture->have_backing_texture()); |
| |
| texture->set_request_priority(100); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| EXPECT_TRUE(ValidateTexture(texture.get(), false)); |
| EXPECT_TRUE(texture->can_acquire_backing_texture()); |
| EXPECT_TRUE(texture->have_backing_texture()); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| resource_manager = nullptr; |
| |
| EXPECT_FALSE(texture->can_acquire_backing_texture()); |
| EXPECT_FALSE(texture->have_backing_texture()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, TextureMovedToNewManager) { |
| scoped_ptr<PrioritizedResourceManager> resource_manager_one = |
| CreateManager(1); |
| scoped_ptr<PrioritizedResourceManager> resource_manager_two = |
| CreateManager(1); |
| scoped_ptr<PrioritizedResource> texture = |
| resource_manager_one->CreateTexture(texture_size_, texture_format_); |
| |
| // Texture is initially invalid, but it will become available. |
| EXPECT_FALSE(texture->have_backing_texture()); |
| |
| texture->set_request_priority(100); |
| PrioritizeTexturesAndBackings(resource_manager_one.get()); |
| |
| EXPECT_TRUE(ValidateTexture(texture.get(), false)); |
| EXPECT_TRUE(texture->can_acquire_backing_texture()); |
| EXPECT_TRUE(texture->have_backing_texture()); |
| |
| texture->SetTextureManager(NULL); |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager_one->ClearAllMemory(resource_provider()); |
| } |
| resource_manager_one = nullptr; |
| |
| EXPECT_FALSE(texture->can_acquire_backing_texture()); |
| EXPECT_FALSE(texture->have_backing_texture()); |
| |
| texture->SetTextureManager(resource_manager_two.get()); |
| |
| PrioritizeTexturesAndBackings(resource_manager_two.get()); |
| |
| EXPECT_TRUE(ValidateTexture(texture.get(), false)); |
| EXPECT_TRUE(texture->can_acquire_backing_texture()); |
| EXPECT_TRUE(texture->have_backing_texture()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager_two->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, |
| RenderSurfacesReduceMemoryAvailableOutsideRootSurface) { |
| const size_t kMaxTextures = 8; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| |
| // Half of the memory is taken by surfaces (with high priority place-holder) |
| scoped_ptr<PrioritizedResource> render_surface_place_holder = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( |
| TexturesMemorySize(4)); |
| render_surface_place_holder->set_request_priority( |
| PriorityCalculator::RenderSurfacePriority()); |
| |
| // Create textures to fill our memory limit. |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| |
| // Set decreasing non-visible priorities outside root surface. |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100 + i); |
| |
| // Only lower half should be available. |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| EXPECT_TRUE(ValidateTexture(textures[0].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[3].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[4].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[7].get(), false)); |
| |
| // Set increasing non-visible priorities outside root surface. |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100 - i); |
| |
| // Only upper half should be available. |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| EXPECT_FALSE(ValidateTexture(textures[0].get(), false)); |
| EXPECT_FALSE(ValidateTexture(textures[3].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[4].get(), false)); |
| EXPECT_TRUE(ValidateTexture(textures[7].get(), false)); |
| |
| EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_EQ(TexturesMemorySize(4), |
| resource_manager->MemoryForSelfManagedTextures()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_EQ(TexturesMemorySize(8), |
| resource_manager->MaxMemoryNeededBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, |
| RenderSurfacesReduceMemoryAvailableForRequestLate) { |
| const size_t kMaxTextures = 8; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| |
| // Half of the memory is taken by surfaces (with high priority place-holder) |
| scoped_ptr<PrioritizedResource> render_surface_place_holder = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( |
| TexturesMemorySize(4)); |
| render_surface_place_holder->set_request_priority( |
| PriorityCalculator::RenderSurfacePriority()); |
| |
| // Create textures to fill our memory limit. |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| |
| // Set equal priorities. |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100); |
| |
| // The first four to be requested late will be available. |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (unsigned i = 0; i < kMaxTextures; ++i) |
| EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); |
| for (unsigned i = 0; i < kMaxTextures; i += 2) |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), true)); |
| for (unsigned i = 1; i < kMaxTextures; i += 2) |
| EXPECT_FALSE(ValidateTexture(textures[i].get(), true)); |
| |
| EXPECT_EQ(TexturesMemorySize(4), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_EQ(TexturesMemorySize(4), |
| resource_manager->MemoryForSelfManagedTextures()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_EQ(TexturesMemorySize(8), |
| resource_manager->MaxMemoryNeededBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, |
| WhenRenderSurfaceNotAvailableTexturesAlsoNotAvailable) { |
| const size_t kMaxTextures = 8; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| |
| // Half of the memory is taken by surfaces (with high priority place-holder) |
| scoped_ptr<PrioritizedResource> render_surface_place_holder = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| render_surface_place_holder->SetToSelfManagedMemoryPlaceholder( |
| TexturesMemorySize(4)); |
| render_surface_place_holder->set_request_priority( |
| PriorityCalculator::RenderSurfacePriority()); |
| |
| // Create textures to fill our memory limit. |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| |
| // Set 6 visible textures in the root surface, and 2 in a child surface. |
| for (size_t i = 0; i < 6; ++i) { |
| textures[i]-> |
| set_request_priority(PriorityCalculator::VisiblePriority(true)); |
| } |
| for (size_t i = 6; i < 8; ++i) { |
| textures[i]-> |
| set_request_priority(PriorityCalculator::VisiblePriority(false)); |
| } |
| |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // Unable to request_late textures in the child surface. |
| EXPECT_FALSE(ValidateTexture(textures[6].get(), true)); |
| EXPECT_FALSE(ValidateTexture(textures[7].get(), true)); |
| |
| // Root surface textures are valid. |
| for (size_t i = 0; i < 6; ++i) |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); |
| |
| EXPECT_EQ(TexturesMemorySize(6), resource_manager->MemoryAboveCutoffBytes()); |
| EXPECT_EQ(TexturesMemorySize(2), |
| resource_manager->MemoryForSelfManagedTextures()); |
| EXPECT_LE(resource_manager->MemoryUseBytes(), |
| resource_manager->MemoryAboveCutoffBytes()); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, RequestLateBackingsSorting) { |
| const size_t kMaxTextures = 8; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); |
| |
| // Create textures to fill our memory limit. |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| |
| // Set equal priorities, and allocate backings for all textures. |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (unsigned i = 0; i < kMaxTextures; ++i) |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); |
| |
| // Drop the memory limit and prioritize (none will be above the threshold, |
| // but they still have backings because ReduceMemory hasn't been called). |
| resource_manager->SetMaxMemoryLimitBytes( |
| TexturesMemorySize(kMaxTextures / 2)); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // Push half of them back over the limit. |
| for (size_t i = 0; i < kMaxTextures; i += 2) |
| EXPECT_TRUE(textures[i]->RequestLate()); |
| |
| // Push the priorities to the backings array and sort the backings array |
| ResourceManagerUpdateBackingsPriorities(resource_manager.get()); |
| |
| // Assert that the backings list be sorted with the below-limit backings |
| // before the above-limit backings. |
| ResourceManagerAssertInvariants(resource_manager.get()); |
| |
| // Make sure that we have backings for all of the textures. |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| EXPECT_TRUE(textures[i]->have_backing_texture()); |
| |
| // Make sure that only the request_late textures are above the priority |
| // cutoff |
| for (size_t i = 0; i < kMaxTextures; i += 2) |
| EXPECT_TRUE(TextureBackingIsAbovePriorityCutoff(textures[i].get())); |
| for (size_t i = 1; i < kMaxTextures; i += 2) |
| EXPECT_FALSE(TextureBackingIsAbovePriorityCutoff(textures[i].get())); |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, ClearUploadsToEvictedResources) { |
| const size_t kMaxTextures = 4; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(kMaxTextures)); |
| |
| // Create textures to fill our memory limit. |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| |
| // Set equal priorities, and allocate backings for all textures. |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| textures[i]->set_request_priority(100); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| for (unsigned i = 0; i < kMaxTextures; ++i) |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); |
| |
| ResourceUpdateQueue queue; |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| const ResourceUpdate upload = ResourceUpdate::Create( |
| textures[i].get(), NULL, gfx::Rect(), gfx::Rect(), gfx::Vector2d()); |
| queue.AppendFullUpload(upload); |
| } |
| |
| // Make sure that we have backings for all of the textures. |
| for (size_t i = 0; i < kMaxTextures; ++i) |
| EXPECT_TRUE(textures[i]->have_backing_texture()); |
| |
| queue.ClearUploadsToEvictedResources(); |
| EXPECT_EQ(4u, queue.FullUploadSize()); |
| |
| resource_manager->ReduceMemoryOnImplThread( |
| TexturesMemorySize(1), |
| PriorityCalculator::AllowEverythingCutoff(), |
| resource_provider()); |
| queue.ClearUploadsToEvictedResources(); |
| EXPECT_EQ(1u, queue.FullUploadSize()); |
| |
| resource_manager->ReduceMemoryOnImplThread( |
| 0, PriorityCalculator::AllowEverythingCutoff(), resource_provider()); |
| queue.ClearUploadsToEvictedResources(); |
| EXPECT_EQ(0u, queue.FullUploadSize()); |
| } |
| |
| TEST_F(PrioritizedResourceTest, UsageStatistics) { |
| const size_t kMaxTextures = 5; |
| scoped_ptr<PrioritizedResourceManager> resource_manager = |
| CreateManager(kMaxTextures); |
| scoped_ptr<PrioritizedResource> textures[kMaxTextures]; |
| |
| for (size_t i = 0; i < kMaxTextures; ++i) { |
| textures[i] = |
| resource_manager->CreateTexture(texture_size_, texture_format_); |
| } |
| |
| textures[0]-> |
| set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); |
| textures[1]-> |
| set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff()); |
| textures[2]->set_request_priority( |
| PriorityCalculator::AllowVisibleAndNearbyCutoff() - 1); |
| textures[3]-> |
| set_request_priority(PriorityCalculator::AllowVisibleAndNearbyCutoff()); |
| textures[4]->set_request_priority( |
| PriorityCalculator::AllowVisibleAndNearbyCutoff() + 1); |
| |
| // Set max limit to 2 textures. |
| resource_manager->SetMaxMemoryLimitBytes(TexturesMemorySize(2)); |
| PrioritizeTexturesAndBackings(resource_manager.get()); |
| |
| // The first two textures should be available, others should not. |
| for (size_t i = 0; i < 2; ++i) |
| EXPECT_TRUE(ValidateTexture(textures[i].get(), false)); |
| for (size_t i = 2; i < kMaxTextures; ++i) |
| EXPECT_FALSE(ValidateTexture(textures[i].get(), false)); |
| |
| // Validate the statistics. |
| { |
| DebugScopedSetImplThread impl_thread(&proxy_); |
| EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); |
| EXPECT_EQ(TexturesMemorySize(1), resource_manager->MemoryVisibleBytes()); |
| EXPECT_EQ(TexturesMemorySize(3), |
| resource_manager->MemoryVisibleAndNearbyBytes()); |
| } |
| |
| // Re-prioritize the textures, but do not push the values to backings. |
| textures[0]-> |
| set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); |
| textures[1]-> |
| set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); |
| textures[2]-> |
| set_request_priority(PriorityCalculator::AllowVisibleOnlyCutoff() - 1); |
| textures[3]->set_request_priority( |
| PriorityCalculator::AllowVisibleAndNearbyCutoff() - 1); |
| textures[4]-> |
| set_request_priority(PriorityCalculator::AllowVisibleAndNearbyCutoff()); |
| resource_manager->PrioritizeTextures(); |
| |
| // Verify that we still see the old values. |
| { |
| DebugScopedSetImplThread impl_thread(&proxy_); |
| EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); |
| EXPECT_EQ(TexturesMemorySize(1), resource_manager->MemoryVisibleBytes()); |
| EXPECT_EQ(TexturesMemorySize(3), |
| resource_manager->MemoryVisibleAndNearbyBytes()); |
| } |
| |
| // Push priorities to backings, and verify we see the new values. |
| { |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->PushTexturePrioritiesToBackings(); |
| EXPECT_EQ(TexturesMemorySize(2), resource_manager->MemoryUseBytes()); |
| EXPECT_EQ(TexturesMemorySize(3), resource_manager->MemoryVisibleBytes()); |
| EXPECT_EQ(TexturesMemorySize(4), |
| resource_manager->MemoryVisibleAndNearbyBytes()); |
| } |
| |
| DebugScopedSetImplThreadAndMainThreadBlocked |
| impl_thread_and_main_thread_blocked(&proxy_); |
| resource_manager->ClearAllMemory(resource_provider()); |
| } |
| |
| } // namespace |
| } // namespace cc |