Home | History | Annotate | Download | only in renderer_host
      1 // Copyright 2013 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 "content/browser/renderer_host/software_frame_manager.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/memory/scoped_vector.h"
     10 #include "base/memory/shared_memory.h"
     11 #include "base/sys_info.h"
     12 #include "content/common/host_shared_bitmap_manager.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 namespace content {
     16 
     17 class FakeSoftwareFrameManagerClient : public SoftwareFrameManagerClient {
     18  public:
     19   FakeSoftwareFrameManagerClient()
     20       : evicted_count_(0), weak_ptr_factory_(this) {
     21     software_frame_manager_.reset(new SoftwareFrameManager(
     22         weak_ptr_factory_.GetWeakPtr()));
     23   }
     24   virtual ~FakeSoftwareFrameManagerClient() {
     25     HostSharedBitmapManager::current()->ProcessRemoved(
     26         base::GetCurrentProcessHandle());
     27   }
     28   virtual void SoftwareFrameWasFreed(uint32 output_surface_id,
     29                                      unsigned frame_id) OVERRIDE {
     30     freed_frames_.push_back(std::make_pair(output_surface_id, frame_id));
     31   }
     32   virtual void ReleaseReferencesToSoftwareFrame() OVERRIDE {
     33     ++evicted_count_;
     34   }
     35 
     36   bool SwapToNewFrame(uint32 output_surface, unsigned frame_id) {
     37     cc::SoftwareFrameData frame;
     38     frame.id = frame_id;
     39     frame.size = gfx::Size(1, 1);
     40     frame.damage_rect = gfx::Rect(frame.size);
     41     frame.bitmap_id = cc::SharedBitmap::GenerateId();
     42     scoped_ptr<base::SharedMemory> memory =
     43         make_scoped_ptr(new base::SharedMemory);
     44     memory->CreateAnonymous(4);
     45     HostSharedBitmapManager::current()->ChildAllocatedSharedBitmap(
     46         4, memory->handle(), base::GetCurrentProcessHandle(), frame.bitmap_id);
     47     allocated_memory_.push_back(memory.release());
     48     return software_frame_manager_->SwapToNewFrame(
     49         output_surface, &frame, 1.0, base::GetCurrentProcessHandle());
     50   }
     51 
     52   SoftwareFrameManager* software_frame_manager() {
     53     return software_frame_manager_.get();
     54   }
     55   size_t freed_frame_count() const { return freed_frames_.size(); }
     56   size_t evicted_frame_count() const { return evicted_count_; }
     57 
     58  private:
     59   std::vector<std::pair<uint32,unsigned> > freed_frames_;
     60   size_t evicted_count_;
     61   ScopedVector<base::SharedMemory> allocated_memory_;
     62 
     63   scoped_ptr<SoftwareFrameManager> software_frame_manager_;
     64   base::WeakPtrFactory<FakeSoftwareFrameManagerClient>
     65       weak_ptr_factory_;
     66 
     67   DISALLOW_COPY_AND_ASSIGN(FakeSoftwareFrameManagerClient);
     68 };
     69 
     70 class SoftwareFrameManagerTest : public testing::Test {
     71  public:
     72   SoftwareFrameManagerTest() {}
     73   void AllocateClients(size_t num_clients) {
     74     for (size_t i = 0; i < num_clients; ++i)
     75       clients_.push_back(new FakeSoftwareFrameManagerClient);
     76   }
     77   void FreeClients() {
     78     for (size_t i = 0; i < clients_.size(); ++i)
     79       delete clients_[i];
     80     clients_.clear();
     81   }
     82   size_t MaxNumberOfSavedFrames() const {
     83     size_t result =
     84         RendererFrameManager::GetInstance()->max_number_of_saved_frames();
     85     return result;
     86   }
     87 
     88  protected:
     89   std::vector<FakeSoftwareFrameManagerClient*> clients_;
     90 
     91  private:
     92   DISALLOW_COPY_AND_ASSIGN(SoftwareFrameManagerTest);
     93 };
     94 
     95 TEST_F(SoftwareFrameManagerTest, DoNotEvictVisible) {
     96   // Create twice as many frames as are allowed.
     97   AllocateClients(2 * MaxNumberOfSavedFrames());
     98 
     99   // Swap a visible frame to all clients_. Because they are all visible,
    100   // the should not be evicted.
    101   for (size_t i = 0; i < clients_.size(); ++i) {
    102     bool swap_result = clients_[i]->SwapToNewFrame(
    103         static_cast<uint32>(i), 0);
    104     clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
    105     EXPECT_TRUE(swap_result);
    106     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    107     EXPECT_EQ(0u, clients_[i]->freed_frame_count());
    108   }
    109   for (size_t i = 0; i < clients_.size(); ++i) {
    110     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    111     EXPECT_EQ(0u, clients_[i]->freed_frame_count());
    112   }
    113 
    114   // Swap another frame and make sure the original was freed (but not evicted).
    115   for (size_t i = 0; i < clients_.size(); ++i) {
    116     bool swap_result = clients_[i]->SwapToNewFrame(
    117         static_cast<uint32>(i), 1);
    118     clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
    119     EXPECT_TRUE(swap_result);
    120     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    121     EXPECT_EQ(1u, clients_[i]->freed_frame_count());
    122   }
    123   for (size_t i = 0; i < clients_.size(); ++i) {
    124     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    125     EXPECT_EQ(1u, clients_[i]->freed_frame_count());
    126   }
    127 
    128   // Mark the frames as nonvisible and make sure they start getting evicted.
    129   for (size_t i = 0; i < clients_.size(); ++i) {
    130     clients_[i]->software_frame_manager()->SetVisibility(false);
    131     if (clients_.size() - i > MaxNumberOfSavedFrames()) {
    132       EXPECT_EQ(1u, clients_[i]->evicted_frame_count());
    133       EXPECT_EQ(2u, clients_[i]->freed_frame_count());
    134     } else {
    135       EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    136       EXPECT_EQ(1u, clients_[i]->freed_frame_count());
    137     }
    138   }
    139 
    140   // Clean up.
    141   FreeClients();
    142 }
    143 
    144 TEST_F(SoftwareFrameManagerTest, DoNotEvictDuringSwap) {
    145   // Create twice as many frames as are allowed.
    146   AllocateClients(2 * MaxNumberOfSavedFrames());
    147 
    148   // Swap a visible frame to all clients_. Because they are all visible,
    149   // the should not be evicted.
    150   for (size_t i = 0; i < clients_.size(); ++i) {
    151     bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
    152     clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
    153     EXPECT_TRUE(swap_result);
    154     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    155     EXPECT_EQ(0u, clients_[i]->freed_frame_count());
    156   }
    157   for (size_t i = 0; i < clients_.size(); ++i) {
    158     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    159     EXPECT_EQ(0u, clients_[i]->freed_frame_count());
    160   }
    161 
    162   // Now create a test non-visible client, and swap a non-visible frame in.
    163   scoped_ptr<FakeSoftwareFrameManagerClient> test_client(
    164       new FakeSoftwareFrameManagerClient);
    165   test_client->software_frame_manager()->SetVisibility(false);
    166   {
    167     bool swap_result = test_client->SwapToNewFrame(
    168         static_cast<uint32>(500), 0);
    169     EXPECT_TRUE(swap_result);
    170     EXPECT_EQ(0u, test_client->evicted_frame_count());
    171     EXPECT_EQ(0u, test_client->freed_frame_count());
    172     test_client->software_frame_manager()->SwapToNewFrameComplete(false);
    173     EXPECT_EQ(1u, test_client->evicted_frame_count());
    174     EXPECT_EQ(1u, test_client->freed_frame_count());
    175   }
    176 
    177   // Clean up.
    178   FreeClients();
    179 }
    180 
    181 TEST_F(SoftwareFrameManagerTest, Cleanup) {
    182   // Create twice as many frames as are allowed.
    183   AllocateClients(2 * MaxNumberOfSavedFrames());
    184 
    185   // Swap a visible frame to all clients_. Because they are all visible,
    186   // the should not be evicted.
    187   for (size_t i = 0; i < clients_.size(); ++i) {
    188     bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
    189     clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
    190     EXPECT_TRUE(swap_result);
    191     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    192     EXPECT_EQ(0u, clients_[i]->freed_frame_count());
    193   }
    194 
    195   // Destroy them.
    196   FreeClients();
    197 
    198   // Create the maximum number of frames, all non-visible. They should not
    199   // be evicted, because the previous frames were cleaned up at destruction.
    200   AllocateClients(MaxNumberOfSavedFrames());
    201   for (size_t i = 0; i < clients_.size(); ++i) {
    202     cc::SoftwareFrameData frame;
    203     bool swap_result = clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
    204     clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
    205     EXPECT_TRUE(swap_result);
    206     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    207     EXPECT_EQ(0u, clients_[i]->freed_frame_count());
    208   }
    209   for (size_t i = 0; i < clients_.size(); ++i) {
    210     EXPECT_EQ(0u, clients_[i]->evicted_frame_count());
    211     EXPECT_EQ(0u, clients_[i]->freed_frame_count());
    212   }
    213 
    214   // Clean up.
    215   FreeClients();
    216 }
    217 
    218 TEST_F(SoftwareFrameManagerTest, EvictVersusFree) {
    219   // Create twice as many frames as are allowed and swap a visible frame to all
    220   // clients_. Because they are all visible, the should not be evicted.
    221   AllocateClients(2 * MaxNumberOfSavedFrames());
    222   for (size_t i = 0; i < clients_.size(); ++i) {
    223     clients_[i]->SwapToNewFrame(static_cast<uint32>(i), 0);
    224     clients_[i]->software_frame_manager()->SwapToNewFrameComplete(true);
    225   }
    226 
    227   // Create a test client with a frame that is not evicted.
    228   scoped_ptr<FakeSoftwareFrameManagerClient> test_client(
    229       new FakeSoftwareFrameManagerClient);
    230   bool swap_result = test_client->SwapToNewFrame(static_cast<uint32>(500), 0);
    231   EXPECT_TRUE(swap_result);
    232   test_client->software_frame_manager()->SwapToNewFrameComplete(true);
    233   EXPECT_EQ(0u, test_client->evicted_frame_count());
    234   EXPECT_EQ(0u, test_client->freed_frame_count());
    235 
    236   // Take out a reference on the current frame and make the memory manager
    237   // evict it. The frame will not be freed until this reference is released.
    238   cc::TextureMailbox mailbox;
    239   scoped_ptr<cc::SingleReleaseCallback> callback;
    240   test_client->software_frame_manager()->GetCurrentFrameMailbox(
    241       &mailbox, &callback);
    242   test_client->software_frame_manager()->SetVisibility(false);
    243   EXPECT_EQ(1u, test_client->evicted_frame_count());
    244   EXPECT_EQ(0u, test_client->freed_frame_count());
    245 
    246   // Swap a few frames. The frames will be freed as they are swapped out.
    247   for (size_t frame = 0; frame < 10; ++frame) {
    248     bool swap_result = test_client->SwapToNewFrame(
    249         static_cast<uint32>(500), 1 + static_cast<int>(frame));
    250     EXPECT_TRUE(swap_result);
    251     test_client->software_frame_manager()->SwapToNewFrameComplete(true);
    252     EXPECT_EQ(frame, test_client->freed_frame_count());
    253     EXPECT_EQ(1u, test_client->evicted_frame_count());
    254   }
    255 
    256   // The reference to the frame that we didn't free is in the callback
    257   // object. It will go away when the callback is destroyed.
    258   EXPECT_EQ(9u, test_client->freed_frame_count());
    259   EXPECT_EQ(1u, test_client->evicted_frame_count());
    260   callback->Run(0, false);
    261   callback.reset();
    262   EXPECT_EQ(10u, test_client->freed_frame_count());
    263   EXPECT_EQ(1u, test_client->evicted_frame_count());
    264 
    265   FreeClients();
    266 }
    267 
    268 }  // namespace content
    269