• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*> {
operator ()BASE_HASH_NAMESPACE::hash19   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:
TrackMemoryAllocatedChange(size_t,size_t,gpu::gles2::MemoryTracker::Pool)28   virtual void TrackMemoryAllocatedChange(
29       size_t /* old_size */,
30       size_t /* new_size */,
31       gpu::gles2::MemoryTracker::Pool /* pool */) OVERRIDE {
32   }
EnsureGPUMemoryAvailable(size_t)33   virtual bool EnsureGPUMemoryAvailable(size_t /* size_needed */) OVERRIDE {
34     return true;
35   }
36  private:
~FakeMemoryTracker()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 
GetClientStatsForLastManage()53   static const ClientMemoryStatMap& GetClientStatsForLastManage() {
54     return client_memory_stats_for_last_manage_;
55   }
ClearAllStats()56   static void ClearAllStats() {
57     client_memory_stats_for_last_manage_.clear();
58   }
AddClientStat(GpuMemoryManagerClient * client,const MemoryAllocation & allocation)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
FakeClient(GpuMemoryManager * memmgr,GpuMemoryManagerClient * share_group)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
FakeClient(GpuMemoryManager * memmgr,int32 surface_id,bool visible)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 
~FakeClient()113   virtual ~FakeClient() {
114     client_state_.reset();
115     tracking_group_.reset();
116     memory_tracker_ = NULL;
117   }
118 
SetMemoryAllocation(const MemoryAllocation & alloc)119   virtual void SetMemoryAllocation(const MemoryAllocation& alloc) OVERRIDE {
120     allocation_ = alloc;
121     ClientAssignmentCollector::AddClientStat(this, alloc);
122   }
123 
SuggestHaveFrontBuffer(bool suggest_have_frontbuffer)124   virtual void SuggestHaveFrontBuffer(bool suggest_have_frontbuffer) OVERRIDE {
125     suggest_have_frontbuffer_ = suggest_have_frontbuffer;
126   }
127 
GetTotalGpuMemory(uint64 * bytes)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   }
SetTotalGpuMemory(uint64 bytes)135   void SetTotalGpuMemory(uint64 bytes) { total_gpu_memory_ = bytes; }
136 
GetMemoryTracker() const137   virtual gpu::gles2::MemoryTracker* GetMemoryTracker() const OVERRIDE {
138     if (share_group_)
139       return share_group_->GetMemoryTracker();
140     return memory_tracker_.get();
141   }
142 
GetSurfaceSize() const143   virtual gfx::Size GetSurfaceSize() const OVERRIDE {
144     return surface_size_;
145   }
SetSurfaceSize(gfx::Size size)146   void SetSurfaceSize(gfx::Size size) { surface_size_ = size; }
147 
SetVisible(bool visible)148   void SetVisible(bool visible) {
149     client_state_->SetVisible(visible);
150   }
151 
BytesWhenVisible() const152   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 
GpuMemoryManagerTest()161   GpuMemoryManagerTest()
162       : memmgr_(0, kFrontbufferLimitForTest) {
163     memmgr_.TestingDisableScheduleManage();
164   }
165 
SetUp()166   virtual void SetUp() {
167   }
168 
GenerateUniqueSurfaceId()169   static int32 GenerateUniqueSurfaceId() {
170     static int32 surface_id_ = 1;
171     return surface_id_++;
172   }
173 
IsAllocationForegroundForSurfaceYes(const MemoryAllocation & alloc)174   bool IsAllocationForegroundForSurfaceYes(
175       const MemoryAllocation& alloc) {
176     return true;
177   }
IsAllocationBackgroundForSurfaceYes(const MemoryAllocation & alloc)178   bool IsAllocationBackgroundForSurfaceYes(
179       const MemoryAllocation& alloc) {
180     return true;
181   }
IsAllocationHibernatedForSurfaceYes(const MemoryAllocation & alloc)182   bool IsAllocationHibernatedForSurfaceYes(
183       const MemoryAllocation& alloc) {
184     return true;
185   }
IsAllocationForegroundForSurfaceNo(const MemoryAllocation & alloc)186   bool IsAllocationForegroundForSurfaceNo(
187       const MemoryAllocation& alloc) {
188     return alloc.bytes_limit_when_visible != 0;
189   }
IsAllocationBackgroundForSurfaceNo(const MemoryAllocation & alloc)190   bool IsAllocationBackgroundForSurfaceNo(
191       const MemoryAllocation& alloc) {
192     return alloc.bytes_limit_when_visible != 0;
193   }
IsAllocationHibernatedForSurfaceNo(const MemoryAllocation & alloc)194   bool IsAllocationHibernatedForSurfaceNo(
195       const MemoryAllocation& alloc) {
196     return alloc.bytes_limit_when_visible == 0;
197   }
198 
Manage()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.
TEST_F(GpuMemoryManagerTest,TestManageBasicFunctionality)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.
TEST_F(GpuMemoryManagerTest,TestManageChangingVisibility)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.
TEST_F(GpuMemoryManagerTest,TestManageManyVisibleStubs)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.
TEST_F(GpuMemoryManagerTest,TestManageManyNotVisibleStubs)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.
TEST_F(GpuMemoryManagerTest,TestManageChangingLastUsedTime)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.
TEST_F(GpuMemoryManagerTest,TestManageChangingImportanceShareGroup)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