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.
5 #include "content/common/gpu/gpu_memory_manager.h"
7 #include "content/common/gpu/gpu_memory_manager_client.h"
8 #include "content/common/gpu/gpu_memory_tracking.h"
9 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/gfx/geometry/size_conversions.h"
13 using gpu::MemoryAllocation
;
15 class FakeMemoryTracker
: public gpu::gles2::MemoryTracker
{
17 void TrackMemoryAllocatedChange(
18 size_t /* old_size */,
19 size_t /* new_size */,
20 gpu::gles2::MemoryTracker::Pool
/* pool */) override
{}
21 bool EnsureGPUMemoryAvailable(size_t /* size_needed */) override
{
24 uint64_t ClientTracingId() const override
{ return 0; }
25 int ClientId() const override
{ return 0; }
28 ~FakeMemoryTracker() override
{}
33 // This class is used to collect all stub assignments during a
35 class ClientAssignmentCollector
{
37 struct ClientMemoryStat
{
38 MemoryAllocation allocation
;
40 typedef base::hash_map
<GpuMemoryManagerClient
*, ClientMemoryStat
>
43 static const ClientMemoryStatMap
& GetClientStatsForLastManage() {
44 return client_memory_stats_for_last_manage_
;
46 static void ClearAllStats() {
47 client_memory_stats_for_last_manage_
.clear();
49 static void AddClientStat(GpuMemoryManagerClient
* client
,
50 const MemoryAllocation
& allocation
) {
51 DCHECK(!client_memory_stats_for_last_manage_
.count(client
));
52 client_memory_stats_for_last_manage_
[client
].allocation
= allocation
;
56 static ClientMemoryStatMap client_memory_stats_for_last_manage_
;
59 ClientAssignmentCollector::ClientMemoryStatMap
60 ClientAssignmentCollector::client_memory_stats_for_last_manage_
;
62 class FakeClient
: public GpuMemoryManagerClient
{
64 GpuMemoryManager
* memmgr_
;
65 bool suggest_have_frontbuffer_
;
66 MemoryAllocation allocation_
;
67 uint64 total_gpu_memory_
;
68 gfx::Size surface_size_
;
69 GpuMemoryManagerClient
* share_group_
;
70 scoped_refptr
<gpu::gles2::MemoryTracker
> memory_tracker_
;
71 scoped_ptr
<GpuMemoryTrackingGroup
> tracking_group_
;
72 scoped_ptr
<GpuMemoryManagerClientState
> client_state_
;
74 // This will create a client with no surface
75 FakeClient(GpuMemoryManager
* memmgr
, GpuMemoryManagerClient
* share_group
)
77 suggest_have_frontbuffer_(false),
79 share_group_(share_group
),
80 memory_tracker_(NULL
) {
82 memory_tracker_
= new FakeMemoryTracker();
83 tracking_group_
.reset(
84 memmgr_
->CreateTrackingGroup(0, memory_tracker_
.get()));
86 client_state_
.reset(memmgr_
->CreateClientState(this, false, true));
89 // This will create a client with a surface
90 FakeClient(GpuMemoryManager
* memmgr
, int32 surface_id
, bool visible
)
92 suggest_have_frontbuffer_(false),
95 memory_tracker_(NULL
) {
96 memory_tracker_
= new FakeMemoryTracker();
97 tracking_group_
.reset(
98 memmgr_
->CreateTrackingGroup(0, memory_tracker_
.get()));
100 memmgr_
->CreateClientState(this, surface_id
!= 0, visible
));
103 ~FakeClient() override
{
104 client_state_
.reset();
105 tracking_group_
.reset();
106 memory_tracker_
= NULL
;
109 void SetMemoryAllocation(const MemoryAllocation
& alloc
) override
{
111 ClientAssignmentCollector::AddClientStat(this, alloc
);
114 void SuggestHaveFrontBuffer(bool suggest_have_frontbuffer
) override
{
115 suggest_have_frontbuffer_
= suggest_have_frontbuffer
;
118 bool GetTotalGpuMemory(uint64
* bytes
) override
{
119 if (total_gpu_memory_
) {
120 *bytes
= total_gpu_memory_
;
125 void SetTotalGpuMemory(uint64 bytes
) { total_gpu_memory_
= bytes
; }
127 gpu::gles2::MemoryTracker
* GetMemoryTracker() const override
{
129 return share_group_
->GetMemoryTracker();
130 return memory_tracker_
.get();
133 gfx::Size
GetSurfaceSize() const override
{ return surface_size_
; }
134 void SetSurfaceSize(gfx::Size size
) { surface_size_
= size
; }
136 void SetVisible(bool visible
) {
137 client_state_
->SetVisible(visible
);
140 uint64
BytesWhenVisible() const {
141 return allocation_
.bytes_limit_when_visible
;
145 class GpuMemoryManagerTest
: public testing::Test
{
147 static const uint64 kFrontbufferLimitForTest
= 3;
149 GpuMemoryManagerTest()
150 : memmgr_(0, kFrontbufferLimitForTest
) {
151 memmgr_
.TestingDisableScheduleManage();
154 void SetUp() override
{}
156 static int32
GenerateUniqueSurfaceId() {
157 static int32 surface_id_
= 1;
158 return surface_id_
++;
161 bool IsAllocationForegroundForSurfaceYes(
162 const MemoryAllocation
& alloc
) {
165 bool IsAllocationBackgroundForSurfaceYes(
166 const MemoryAllocation
& alloc
) {
169 bool IsAllocationHibernatedForSurfaceYes(
170 const MemoryAllocation
& alloc
) {
173 bool IsAllocationForegroundForSurfaceNo(
174 const MemoryAllocation
& alloc
) {
175 return alloc
.bytes_limit_when_visible
!= 0;
177 bool IsAllocationBackgroundForSurfaceNo(
178 const MemoryAllocation
& alloc
) {
179 return alloc
.bytes_limit_when_visible
!= 0;
181 bool IsAllocationHibernatedForSurfaceNo(
182 const MemoryAllocation
& alloc
) {
183 return alloc
.bytes_limit_when_visible
== 0;
187 ClientAssignmentCollector::ClearAllStats();
191 GpuMemoryManager memmgr_
;
194 // Test GpuMemoryManager::Manage basic functionality.
195 // Expect memory allocation to set suggest_have_frontbuffer/backbuffer
196 // according to visibility and last used time for stubs with surface.
197 // Expect memory allocation to be shared according to share groups for stubs
198 // without a surface.
199 TEST_F(GpuMemoryManagerTest
, TestManageBasicFunctionality
) {
200 // Test stubs with surface.
201 FakeClient
stub1(&memmgr_
, GenerateUniqueSurfaceId(), true),
202 stub2(&memmgr_
, GenerateUniqueSurfaceId(), false);
205 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1
.allocation_
));
206 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2
.allocation_
));
208 // Test stubs without surface, with share group of 1 stub.
209 FakeClient
stub3(&memmgr_
, &stub1
), stub4(&memmgr_
, &stub2
);
212 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1
.allocation_
));
213 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2
.allocation_
));
214 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3
.allocation_
));
215 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4
.allocation_
));
217 // Test stub without surface, with share group of multiple stubs.
218 FakeClient
stub5(&memmgr_
, &stub2
);
221 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4
.allocation_
));
224 // Test GpuMemoryManager::Manage functionality: changing visibility.
225 // Expect memory allocation to set suggest_have_frontbuffer/backbuffer
226 // according to visibility and last used time for stubs with surface.
227 // Expect memory allocation to be shared according to share groups for stubs
228 // without a surface.
229 TEST_F(GpuMemoryManagerTest
, TestManageChangingVisibility
) {
230 FakeClient
stub1(&memmgr_
, GenerateUniqueSurfaceId(), true),
231 stub2(&memmgr_
, GenerateUniqueSurfaceId(), false);
233 FakeClient
stub3(&memmgr_
, &stub1
), stub4(&memmgr_
, &stub2
);
234 FakeClient
stub5(&memmgr_
, &stub2
);
237 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1
.allocation_
));
238 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2
.allocation_
));
239 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3
.allocation_
));
240 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4
.allocation_
));
241 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5
.allocation_
));
243 stub1
.SetVisible(false);
244 stub2
.SetVisible(true);
247 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1
.allocation_
));
248 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2
.allocation_
));
249 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3
.allocation_
));
250 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4
.allocation_
));
251 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5
.allocation_
));
254 // Test GpuMemoryManager::Manage functionality: Test more than threshold number
256 // Expect all allocations to continue to have frontbuffer.
257 TEST_F(GpuMemoryManagerTest
, TestManageManyVisibleStubs
) {
258 FakeClient
stub1(&memmgr_
, GenerateUniqueSurfaceId(), true),
259 stub2(&memmgr_
, GenerateUniqueSurfaceId(), true),
260 stub3(&memmgr_
, GenerateUniqueSurfaceId(), true),
261 stub4(&memmgr_
, GenerateUniqueSurfaceId(), true);
263 FakeClient
stub5(&memmgr_
, &stub1
), stub6(&memmgr_
, &stub2
);
264 FakeClient
stub7(&memmgr_
, &stub2
);
267 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1
.allocation_
));
268 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2
.allocation_
));
269 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub3
.allocation_
));
270 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub4
.allocation_
));
271 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub5
.allocation_
));
272 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub6
.allocation_
));
273 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub7
.allocation_
));
276 // Test GpuMemoryManager::Manage functionality: Test more than threshold number
277 // of not visible stubs.
278 // Expect the stubs surpassing the threshold to not have a backbuffer.
279 TEST_F(GpuMemoryManagerTest
, TestManageManyNotVisibleStubs
) {
280 FakeClient
stub1(&memmgr_
, GenerateUniqueSurfaceId(), true),
281 stub2(&memmgr_
, GenerateUniqueSurfaceId(), true),
282 stub3(&memmgr_
, GenerateUniqueSurfaceId(), true),
283 stub4(&memmgr_
, GenerateUniqueSurfaceId(), true);
284 stub4
.SetVisible(false);
285 stub3
.SetVisible(false);
286 stub2
.SetVisible(false);
287 stub1
.SetVisible(false);
289 FakeClient
stub5(&memmgr_
, &stub1
), stub6(&memmgr_
, &stub4
);
290 FakeClient
stub7(&memmgr_
, &stub1
);
293 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1
.allocation_
));
294 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2
.allocation_
));
295 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub3
.allocation_
));
296 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub4
.allocation_
));
297 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub5
.allocation_
));
298 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub6
.allocation_
));
299 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub7
.allocation_
));
302 // Test GpuMemoryManager::Manage functionality: Test changing the last used
303 // time of stubs when doing so causes change in which stubs surpass threshold.
304 // Expect frontbuffer to be dropped for the older stub.
305 TEST_F(GpuMemoryManagerTest
, TestManageChangingLastUsedTime
) {
306 FakeClient
stub1(&memmgr_
, GenerateUniqueSurfaceId(), true),
307 stub2(&memmgr_
, GenerateUniqueSurfaceId(), true),
308 stub3(&memmgr_
, GenerateUniqueSurfaceId(), true),
309 stub4(&memmgr_
, GenerateUniqueSurfaceId(), true);
311 FakeClient
stub5(&memmgr_
, &stub3
), stub6(&memmgr_
, &stub4
);
312 FakeClient
stub7(&memmgr_
, &stub3
);
314 // Make stub4 be the least-recently-used client
315 stub4
.SetVisible(false);
316 stub3
.SetVisible(false);
317 stub2
.SetVisible(false);
318 stub1
.SetVisible(false);
321 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1
.allocation_
));
322 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2
.allocation_
));
323 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub3
.allocation_
));
324 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub4
.allocation_
));
325 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub5
.allocation_
));
326 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub6
.allocation_
));
327 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub7
.allocation_
));
329 // Make stub3 become the least-recently-used client.
330 stub2
.SetVisible(true);
331 stub2
.SetVisible(false);
332 stub4
.SetVisible(true);
333 stub4
.SetVisible(false);
336 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1
.allocation_
));
337 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2
.allocation_
));
338 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub3
.allocation_
));
339 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub4
.allocation_
));
340 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub5
.allocation_
));
341 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub6
.allocation_
));
342 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub7
.allocation_
));
345 // Test GpuMemoryManager::Manage functionality: Test changing importance of
346 // enough stubs so that every stub in share group crosses threshold.
347 // Expect memory allocation of the stubs without surface to share memory
348 // allocation with the most visible stub in share group.
349 TEST_F(GpuMemoryManagerTest
, TestManageChangingImportanceShareGroup
) {
350 FakeClient
stub_ignore_a(&memmgr_
, GenerateUniqueSurfaceId(), true),
351 stub_ignore_b(&memmgr_
, GenerateUniqueSurfaceId(), false),
352 stub_ignore_c(&memmgr_
, GenerateUniqueSurfaceId(), false);
353 FakeClient
stub1(&memmgr_
, GenerateUniqueSurfaceId(), false),
354 stub2(&memmgr_
, GenerateUniqueSurfaceId(), false);
356 FakeClient
stub3(&memmgr_
, &stub2
), stub4(&memmgr_
, &stub2
);
358 // stub1 and stub2 keep their non-hibernated state because they're
359 // either visible or the 2 most recently used clients (through the
360 // first three checks).
361 stub1
.SetVisible(true);
362 stub2
.SetVisible(true);
364 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub1
.allocation_
));
365 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2
.allocation_
));
366 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub3
.allocation_
));
367 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4
.allocation_
));
369 stub1
.SetVisible(false);
371 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1
.allocation_
));
372 EXPECT_TRUE(IsAllocationForegroundForSurfaceYes(stub2
.allocation_
));
373 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3
.allocation_
));
374 EXPECT_TRUE(IsAllocationForegroundForSurfaceNo(stub4
.allocation_
));
376 stub2
.SetVisible(false);
378 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub1
.allocation_
));
379 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2
.allocation_
));
380 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3
.allocation_
));
381 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4
.allocation_
));
383 // stub_ignore_b will cause stub1 to become hibernated (because
384 // stub_ignore_a, stub_ignore_b, and stub2 are all non-hibernated and more
386 stub_ignore_b
.SetVisible(true);
387 stub_ignore_b
.SetVisible(false);
389 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub1
.allocation_
));
390 EXPECT_TRUE(IsAllocationBackgroundForSurfaceYes(stub2
.allocation_
));
391 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub3
.allocation_
));
392 EXPECT_TRUE(IsAllocationBackgroundForSurfaceNo(stub4
.allocation_
));
394 // stub_ignore_c will cause stub2 to become hibernated (because
395 // stub_ignore_a, stub_ignore_b, and stub_ignore_c are all non-hibernated
396 // and more important).
397 stub_ignore_c
.SetVisible(true);
398 stub_ignore_c
.SetVisible(false);
400 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub1
.allocation_
));
401 EXPECT_TRUE(IsAllocationHibernatedForSurfaceYes(stub2
.allocation_
));
402 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub3
.allocation_
));
403 EXPECT_TRUE(IsAllocationHibernatedForSurfaceNo(stub4
.allocation_
));
406 } // namespace content