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