1 // Copyright (c) 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 "content/common/gpu/gpu_memory_manager.h" 6 #include "content/common/gpu/gpu_memory_manager_client.h" 7 #include "content/common/gpu/gpu_memory_tracking.h" 8 #include "gpu/command_buffer/common/gpu_memory_allocation.h" 9 #include "ui/gfx/size_conversions.h" 10 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 using gpu::MemoryAllocation; 14 15 #if defined(COMPILER_GCC) 16 namespace BASE_HASH_NAMESPACE { 17 template<> 18 struct hash<content::GpuMemoryManagerClient*> { 19 uint64 operator()(content::GpuMemoryManagerClient* ptr) const { 20 return hash<uint64>()(reinterpret_cast<uint64>(ptr)); 21 } 22 }; 23 } // namespace BASE_HASH_NAMESPACE 24 #endif // COMPILER 25 26 class FakeMemoryTracker : public gpu::gles2::MemoryTracker { 27 public: 28 virtual void TrackMemoryAllocatedChange( 29 size_t /* old_size */, 30 size_t /* new_size */, 31 gpu::gles2::MemoryTracker::Pool /* pool */) OVERRIDE { 32 } 33 virtual bool EnsureGPUMemoryAvailable(size_t /* size_needed */) OVERRIDE { 34 return true; 35 } 36 private: 37 virtual ~FakeMemoryTracker() { 38 } 39 }; 40 41 namespace content { 42 43 // This class is used to collect all stub assignments during a 44 // Manage() call. 45 class ClientAssignmentCollector { 46 public: 47 struct ClientMemoryStat { 48 MemoryAllocation allocation; 49 }; 50 typedef base::hash_map<GpuMemoryManagerClient*, ClientMemoryStat> 51 ClientMemoryStatMap; 52 53 static const ClientMemoryStatMap& GetClientStatsForLastManage() { 54 return client_memory_stats_for_last_manage_; 55 } 56 static void ClearAllStats() { 57 client_memory_stats_for_last_manage_.clear(); 58 } 59 static void AddClientStat(GpuMemoryManagerClient* client, 60 const MemoryAllocation& allocation) { 61 DCHECK(!client_memory_stats_for_last_manage_.count(client)); 62 client_memory_stats_for_last_manage_[client].allocation = allocation; 63 } 64 65 private: 66 static ClientMemoryStatMap client_memory_stats_for_last_manage_; 67 }; 68 69 ClientAssignmentCollector::ClientMemoryStatMap 70 ClientAssignmentCollector::client_memory_stats_for_last_manage_; 71 72 class FakeClient : public GpuMemoryManagerClient { 73 public: 74 GpuMemoryManager* memmgr_; 75 bool suggest_have_frontbuffer_; 76 MemoryAllocation allocation_; 77 uint64 total_gpu_memory_; 78 gfx::Size surface_size_; 79 GpuMemoryManagerClient* share_group_; 80 scoped_refptr<gpu::gles2::MemoryTracker> memory_tracker_; 81 scoped_ptr<GpuMemoryTrackingGroup> tracking_group_; 82 scoped_ptr<GpuMemoryManagerClientState> client_state_; 83 84 // This will create a client with no surface 85 FakeClient(GpuMemoryManager* memmgr, GpuMemoryManagerClient* share_group) 86 : memmgr_(memmgr), 87 suggest_have_frontbuffer_(false), 88 total_gpu_memory_(0), 89 share_group_(share_group), 90 memory_tracker_(NULL) { 91 if (!share_group_) { 92 memory_tracker_ = new FakeMemoryTracker(); 93 tracking_group_.reset( 94 memmgr_->CreateTrackingGroup(0, memory_tracker_.get())); 95 } 96 client_state_.reset(memmgr_->CreateClientState(this, false, true)); 97 } 98 99 // This will create a client with a surface 100 FakeClient(GpuMemoryManager* memmgr, int32 surface_id, bool visible) 101 : memmgr_(memmgr), 102 suggest_have_frontbuffer_(false), 103 total_gpu_memory_(0), 104 share_group_(NULL), 105 memory_tracker_(NULL) { 106 memory_tracker_ = new FakeMemoryTracker(); 107 tracking_group_.reset( 108 memmgr_->CreateTrackingGroup(0, memory_tracker_.get())); 109 client_state_.reset( 110 memmgr_->CreateClientState(this, surface_id != 0, visible)); 111 } 112 113 virtual ~FakeClient() { 114 client_state_.reset(); 115 tracking_group_.reset(); 116 memory_tracker_ = NULL; 117 } 118 119 virtual void SetMemoryAllocation(const MemoryAllocation& alloc) OVERRIDE { 120 allocation_ = alloc; 121 ClientAssignmentCollector::AddClientStat(this, alloc); 122 } 123 124 virtual void SuggestHaveFrontBuffer(bool suggest_have_frontbuffer) OVERRIDE { 125 suggest_have_frontbuffer_ = suggest_have_frontbuffer; 126 } 127 128 virtual bool GetTotalGpuMemory(uint64* bytes) OVERRIDE { 129 if (total_gpu_memory_) { 130 *bytes = total_gpu_memory_; 131 return true; 132 } 133 return false; 134 } 135 void SetTotalGpuMemory(uint64 bytes) { total_gpu_memory_ = bytes; } 136 137 virtual gpu::gles2::MemoryTracker* GetMemoryTracker() const OVERRIDE { 138 if (share_group_) 139 return share_group_->GetMemoryTracker(); 140 return memory_tracker_.get(); 141 } 142 143 virtual gfx::Size GetSurfaceSize() const OVERRIDE { 144 return surface_size_; 145 } 146 void SetSurfaceSize(gfx::Size size) { surface_size_ = size; } 147 148 void SetVisible(bool visible) { 149 client_state_->SetVisible(visible); 150 } 151 152 uint64 BytesWhenVisible() const { 153 return allocation_.bytes_limit_when_visible; 154 } 155 }; 156 157 class GpuMemoryManagerTest : public testing::Test { 158 protected: 159 static const uint64 kFrontbufferLimitForTest = 3; 160 161 GpuMemoryManagerTest() 162 : memmgr_(0, kFrontbufferLimitForTest) { 163 memmgr_.TestingDisableScheduleManage(); 164 } 165 166 virtual void SetUp() { 167 } 168 169 static int32 GenerateUniqueSurfaceId() { 170 static int32 surface_id_ = 1; 171 return surface_id_++; 172 } 173 174 bool IsAllocationForegroundForSurfaceYes( 175 const MemoryAllocation& alloc) { 176 return true; 177 } 178 bool IsAllocationBackgroundForSurfaceYes( 179 const MemoryAllocation& alloc) { 180 return true; 181 } 182 bool IsAllocationHibernatedForSurfaceYes( 183 const MemoryAllocation& alloc) { 184 return true; 185 } 186 bool IsAllocationForegroundForSurfaceNo( 187 const MemoryAllocation& alloc) { 188 return alloc.bytes_limit_when_visible != 0; 189 } 190 bool IsAllocationBackgroundForSurfaceNo( 191 const MemoryAllocation& alloc) { 192 return alloc.bytes_limit_when_visible != 0; 193 } 194 bool IsAllocationHibernatedForSurfaceNo( 195 const MemoryAllocation& alloc) { 196 return alloc.bytes_limit_when_visible == 0; 197 } 198 199 void Manage() { 200 ClientAssignmentCollector::ClearAllStats(); 201 memmgr_.Manage(); 202 } 203 204 GpuMemoryManager memmgr_; 205 }; 206 207 // Test GpuMemoryManager::Manage basic functionality. 208 // Expect memory allocation to set suggest_have_frontbuffer/backbuffer 209 // according to visibility and last used time for stubs with surface. 210 // Expect memory allocation to be shared according to share groups for stubs 211 // without a surface. 212 TEST_F(GpuMemoryManagerTest, TestManageBasicFunctionality) { 213 // Test stubs with surface. 214 FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), 215 stub2(&memmgr_, GenerateUniqueSurfaceId(), false); 216 217 Manage(); 218 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); 219 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); 220 221 // Test stubs without surface, with share group of 1 stub. 222 FakeClient stub3(&memmgr_, &stub1), stub4(&memmgr_, &stub2); 223 224 Manage(); 225 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); 226 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); 227 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_)); 228 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_)); 229 230 // Test stub without surface, with share group of multiple stubs. 231 FakeClient stub5(&memmgr_ , &stub2); 232 233 Manage(); 234 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_)); 235 } 236 237 // Test GpuMemoryManager::Manage functionality: changing visibility. 238 // Expect memory allocation to set suggest_have_frontbuffer/backbuffer 239 // according to visibility and last used time for stubs with surface. 240 // Expect memory allocation to be shared according to share groups for stubs 241 // without a surface. 242 TEST_F(GpuMemoryManagerTest, TestManageChangingVisibility) { 243 FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), 244 stub2(&memmgr_, GenerateUniqueSurfaceId(), false); 245 246 FakeClient stub3(&memmgr_, &stub1), stub4(&memmgr_, &stub2); 247 FakeClient stub5(&memmgr_ , &stub2); 248 249 Manage(); 250 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); 251 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); 252 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_)); 253 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_)); 254 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_)); 255 256 stub1.SetVisible(false); 257 stub2.SetVisible(true); 258 259 Manage(); 260 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); 261 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_)); 262 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_)); 263 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_)); 264 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_)); 265 } 266 267 // Test GpuMemoryManager::Manage functionality: Test more than threshold number 268 // of visible stubs. 269 // Expect all allocations to continue to have frontbuffer. 270 TEST_F(GpuMemoryManagerTest, TestManageManyVisibleStubs) { 271 FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), 272 stub2(&memmgr_, GenerateUniqueSurfaceId(), true), 273 stub3(&memmgr_, GenerateUniqueSurfaceId(), true), 274 stub4(&memmgr_, GenerateUniqueSurfaceId(), true); 275 276 FakeClient stub5(&memmgr_ , &stub1), stub6(&memmgr_ , &stub2); 277 FakeClient stub7(&memmgr_ , &stub2); 278 279 Manage(); 280 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); 281 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_)); 282 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub3.allocation_)); 283 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub4.allocation_)); 284 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5.allocation_)); 285 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub6.allocation_)); 286 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub7.allocation_)); 287 } 288 289 // Test GpuMemoryManager::Manage functionality: Test more than threshold number 290 // of not visible stubs. 291 // Expect the stubs surpassing the threshold to not have a backbuffer. 292 TEST_F(GpuMemoryManagerTest, TestManageManyNotVisibleStubs) { 293 FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), 294 stub2(&memmgr_, GenerateUniqueSurfaceId(), true), 295 stub3(&memmgr_, GenerateUniqueSurfaceId(), true), 296 stub4(&memmgr_, GenerateUniqueSurfaceId(), true); 297 stub4.SetVisible(false); 298 stub3.SetVisible(false); 299 stub2.SetVisible(false); 300 stub1.SetVisible(false); 301 302 FakeClient stub5(&memmgr_ , &stub1), stub6(&memmgr_ , &stub4); 303 FakeClient stub7(&memmgr_ , &stub1); 304 305 Manage(); 306 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); 307 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); 308 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub3.allocation_)); 309 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub4.allocation_)); 310 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub5.allocation_)); 311 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub6.allocation_)); 312 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub7.allocation_)); 313 } 314 315 // Test GpuMemoryManager::Manage functionality: Test changing the last used 316 // time of stubs when doing so causes change in which stubs surpass threshold. 317 // Expect frontbuffer to be dropped for the older stub. 318 TEST_F(GpuMemoryManagerTest, TestManageChangingLastUsedTime) { 319 FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true), 320 stub2(&memmgr_, GenerateUniqueSurfaceId(), true), 321 stub3(&memmgr_, GenerateUniqueSurfaceId(), true), 322 stub4(&memmgr_, GenerateUniqueSurfaceId(), true); 323 324 FakeClient stub5(&memmgr_ , &stub3), stub6(&memmgr_ , &stub4); 325 FakeClient stub7(&memmgr_ , &stub3); 326 327 // Make stub4 be the least-recently-used client 328 stub4.SetVisible(false); 329 stub3.SetVisible(false); 330 stub2.SetVisible(false); 331 stub1.SetVisible(false); 332 333 Manage(); 334 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); 335 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); 336 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub3.allocation_)); 337 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub4.allocation_)); 338 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub5.allocation_)); 339 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub6.allocation_)); 340 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub7.allocation_)); 341 342 // Make stub3 become the least-recently-used client. 343 stub2.SetVisible(true); 344 stub2.SetVisible(false); 345 stub4.SetVisible(true); 346 stub4.SetVisible(false); 347 348 Manage(); 349 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); 350 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); 351 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub3.allocation_)); 352 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub4.allocation_)); 353 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub5.allocation_)); 354 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub6.allocation_)); 355 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub7.allocation_)); 356 } 357 358 // Test GpuMemoryManager::Manage functionality: Test changing importance of 359 // enough stubs so that every stub in share group crosses threshold. 360 // Expect memory allocation of the stubs without surface to share memory 361 // allocation with the most visible stub in share group. 362 TEST_F(GpuMemoryManagerTest, TestManageChangingImportanceShareGroup) { 363 FakeClient stub_ignore_a(&memmgr_, GenerateUniqueSurfaceId(), true), 364 stub_ignore_b(&memmgr_, GenerateUniqueSurfaceId(), false), 365 stub_ignore_c(&memmgr_, GenerateUniqueSurfaceId(), false); 366 FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), false), 367 stub2(&memmgr_, GenerateUniqueSurfaceId(), false); 368 369 FakeClient stub3(&memmgr_, &stub2), stub4(&memmgr_, &stub2); 370 371 // stub1 and stub2 keep their non-hibernated state because they're 372 // either visible or the 2 most recently used clients (through the 373 // first three checks). 374 stub1.SetVisible(true); 375 stub2.SetVisible(true); 376 Manage(); 377 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1.allocation_)); 378 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_)); 379 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3.allocation_)); 380 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_)); 381 382 stub1.SetVisible(false); 383 Manage(); 384 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); 385 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2.allocation_)); 386 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_)); 387 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4.allocation_)); 388 389 stub2.SetVisible(false); 390 Manage(); 391 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1.allocation_)); 392 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); 393 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_)); 394 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_)); 395 396 // stub_ignore_b will cause stub1 to become hibernated (because 397 // stub_ignore_a, stub_ignore_b, and stub2 are all non-hibernated and more 398 // important). 399 stub_ignore_b.SetVisible(true); 400 stub_ignore_b.SetVisible(false); 401 Manage(); 402 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub1.allocation_)); 403 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2.allocation_)); 404 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3.allocation_)); 405 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4.allocation_)); 406 407 // stub_ignore_c will cause stub2 to become hibernated (because 408 // stub_ignore_a, stub_ignore_b, and stub_ignore_c are all non-hibernated 409 // and more important). 410 stub_ignore_c.SetVisible(true); 411 stub_ignore_c.SetVisible(false); 412 Manage(); 413 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub1.allocation_)); 414 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub2.allocation_)); 415 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub3.allocation_)); 416 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub4.allocation_)); 417 } 418 419 } // namespace content 420