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
13using gpu::MemoryAllocation;
14
15#if defined(COMPILER_GCC)
16namespace BASE_HASH_NAMESPACE {
17template<>
18struct 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
26class 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
41namespace content {
42
43// This class is used to collect all stub assignments during a
44// Manage() call.
45class 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
69ClientAssignmentCollector::ClientMemoryStatMap
70    ClientAssignmentCollector::client_memory_stats_for_last_manage_;
71
72class 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
157class 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.
212TEST_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.
242TEST_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.
270TEST_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.
292TEST_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.
318TEST_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.
362TEST_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