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