1 // Copyright 2015 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.
6 #include "base/command_line.h"
7 #include "base/memory/discardable_memory.h"
8 #include "base/memory/scoped_vector.h"
9 #include "base/time/time.h"
10 #include "content/child/child_discardable_shared_memory_manager.h"
11 #include "content/child/child_gpu_memory_buffer_manager.h"
12 #include "content/child/child_thread_impl.h"
13 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
14 #include "content/common/host_discardable_shared_memory_manager.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/test/content_browser_test.h"
17 #include "content/public/test/content_browser_test_utils.h"
18 #include "content/shell/browser/shell.h"
19 #include "ui/gfx/buffer_format_util.h"
25 class ChildThreadImplBrowserTest
: public ContentBrowserTest
{
27 ChildThreadImplBrowserTest()
28 : child_gpu_memory_buffer_manager_(nullptr),
29 child_discardable_shared_memory_manager_(nullptr) {}
31 // Overridden from BrowserTestBase:
32 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
33 command_line
->AppendSwitch(switches::kSingleProcess
);
35 void SetUpOnMainThread() override
{
36 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
37 PostTaskToInProcessRendererAndWait(
38 base::Bind(&ChildThreadImplBrowserTest::SetUpOnChildThread
, this));
41 ChildGpuMemoryBufferManager
* child_gpu_memory_buffer_manager() {
42 return child_gpu_memory_buffer_manager_
;
45 ChildDiscardableSharedMemoryManager
*
46 child_discardable_shared_memory_manager() {
47 return child_discardable_shared_memory_manager_
;
51 void SetUpOnChildThread() {
52 child_gpu_memory_buffer_manager_
=
53 ChildThreadImpl::current()->gpu_memory_buffer_manager();
54 child_discardable_shared_memory_manager_
=
55 ChildThreadImpl::current()->discardable_shared_memory_manager();
58 ChildGpuMemoryBufferManager
* child_gpu_memory_buffer_manager_
;
59 ChildDiscardableSharedMemoryManager
* child_discardable_shared_memory_manager_
;
62 IN_PROC_BROWSER_TEST_F(ChildThreadImplBrowserTest
,
63 DISABLED_LockDiscardableMemory
) {
64 const size_t kSize
= 1024 * 1024; // 1MiB.
66 scoped_ptr
<base::DiscardableMemory
> memory
=
67 child_discardable_shared_memory_manager()
68 ->AllocateLockedDiscardableMemory(kSize
);
71 void* addr
= memory
->data();
72 ASSERT_NE(nullptr, addr
);
76 // Purge all unlocked memory.
77 HostDiscardableSharedMemoryManager::current()->SetMemoryLimit(0);
79 // Should fail as memory should have been purged.
80 EXPECT_FALSE(memory
->Lock());
83 IN_PROC_BROWSER_TEST_F(ChildThreadImplBrowserTest
,
84 DISABLED_DiscardableMemoryAddressSpace
) {
85 const size_t kLargeSize
= 4 * 1024 * 1024; // 4MiB.
86 const size_t kNumberOfInstances
= 1024 + 1; // >4GiB total.
88 ScopedVector
<base::DiscardableMemory
> instances
;
89 for (size_t i
= 0; i
< kNumberOfInstances
; ++i
) {
90 scoped_ptr
<base::DiscardableMemory
> memory
=
91 child_discardable_shared_memory_manager()
92 ->AllocateLockedDiscardableMemory(kLargeSize
);
94 void* addr
= memory
->data();
95 ASSERT_NE(nullptr, addr
);
97 instances
.push_back(memory
.Pass());
101 IN_PROC_BROWSER_TEST_F(ChildThreadImplBrowserTest
,
102 DISABLED_ReleaseFreeDiscardableMemory
) {
103 const size_t kSize
= 1024 * 1024; // 1MiB.
105 scoped_ptr
<base::DiscardableMemory
> memory
=
106 child_discardable_shared_memory_manager()
107 ->AllocateLockedDiscardableMemory(kSize
);
112 EXPECT_GE(HostDiscardableSharedMemoryManager::current()->GetBytesAllocated(),
115 child_discardable_shared_memory_manager()->ReleaseFreeMemory();
117 // Busy wait for host memory usage to be reduced.
118 base::TimeTicks end
=
119 base::TimeTicks::Now() + base::TimeDelta::FromSeconds(5);
120 while (base::TimeTicks::Now() < end
) {
121 if (!HostDiscardableSharedMemoryManager::current()->GetBytesAllocated())
125 EXPECT_LT(base::TimeTicks::Now(), end
);
128 enum NativeBufferFlag
{ kDisableNativeBuffers
, kEnableNativeBuffers
};
130 class ChildThreadImplGpuMemoryBufferBrowserTest
131 : public ChildThreadImplBrowserTest
,
132 public testing::WithParamInterface
<
133 ::testing::tuple
<NativeBufferFlag
, gfx::BufferFormat
>> {
135 // Overridden from BrowserTestBase:
136 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
137 ChildThreadImplBrowserTest::SetUpCommandLine(command_line
);
138 NativeBufferFlag native_buffer_flag
= ::testing::get
<0>(GetParam());
139 switch (native_buffer_flag
) {
140 case kEnableNativeBuffers
:
141 command_line
->AppendSwitch(switches::kEnableNativeGpuMemoryBuffers
);
143 case kDisableNativeBuffers
:
144 command_line
->AppendSwitch(switches::kDisableNativeGpuMemoryBuffers
);
150 IN_PROC_BROWSER_TEST_P(ChildThreadImplGpuMemoryBufferBrowserTest
,
152 gfx::BufferFormat format
= ::testing::get
<1>(GetParam());
153 gfx::Size
buffer_size(4, 4);
155 scoped_ptr
<gfx::GpuMemoryBuffer
> buffer
=
156 child_gpu_memory_buffer_manager()->AllocateGpuMemoryBuffer(
157 buffer_size
, format
, gfx::BufferUsage::MAP
);
159 EXPECT_EQ(format
, buffer
->GetFormat());
161 size_t num_planes
= gfx::NumberOfPlanesForBufferFormat(format
);
163 // Map buffer planes.
164 scoped_ptr
<void* []> planes(new void* [num_planes
]);
165 bool rv
= buffer
->Map(planes
.get());
167 EXPECT_TRUE(buffer
->IsMapped());
170 scoped_ptr
<int[]> strides(new int[num_planes
]);
171 buffer
->GetStride(strides
.get());
173 // Write to buffer and check result.
174 for (size_t plane
= 0; plane
< num_planes
; ++plane
) {
175 size_t row_size_in_bytes
= 0;
176 EXPECT_TRUE(gfx::RowSizeForBufferFormatChecked(buffer_size
.width(), format
,
177 plane
, &row_size_in_bytes
));
179 scoped_ptr
<char[]> data(new char[row_size_in_bytes
]);
180 memset(data
.get(), 0x2a + plane
, row_size_in_bytes
);
181 size_t height
= buffer_size
.height() /
182 gfx::SubsamplingFactorForBufferFormat(format
, plane
);
183 for (size_t y
= 0; y
< height
; ++y
) {
184 // Copy |data| to row |y| of |plane| and verify result.
185 memcpy(static_cast<char*>(planes
[plane
]) + y
* strides
[plane
], data
.get(),
187 EXPECT_EQ(memcmp(static_cast<char*>(planes
[plane
]) + y
* strides
[plane
],
188 data
.get(), row_size_in_bytes
),
194 EXPECT_FALSE(buffer
->IsMapped());
197 INSTANTIATE_TEST_CASE_P(
198 ChildThreadImplGpuMemoryBufferBrowserTests
,
199 ChildThreadImplGpuMemoryBufferBrowserTest
,
200 ::testing::Combine(::testing::Values(kDisableNativeBuffers
,
201 kEnableNativeBuffers
),
202 // These formats are guaranteed to work on all platforms.
203 ::testing::Values(gfx::BufferFormat::R_8
,
204 gfx::BufferFormat::RGBA_4444
,
205 gfx::BufferFormat::RGBA_8888
,
206 gfx::BufferFormat::BGRA_8888
,
207 gfx::BufferFormat::YUV_420
)));
210 } // namespace content