OLD | NEW |
| (Empty) |
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. | |
4 | |
5 // This file defines tests that implementations of GpuMemoryBufferFactory should | |
6 // pass in order to be conformant. | |
7 | |
8 #ifndef CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_TEST_TEMPLATE_H_ | |
9 #define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_TEST_TEMPLATE_H_ | |
10 | |
11 #include <stddef.h> | |
12 #include <string.h> | |
13 | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 #include "ui/gfx/buffer_format_util.h" | |
16 | |
17 namespace content { | |
18 | |
19 template <typename GpuMemoryBufferImplType> | |
20 class GpuMemoryBufferImplTest : public testing::Test { | |
21 public: | |
22 GpuMemoryBufferImpl::DestructionCallback AllocateGpuMemoryBuffer( | |
23 const gfx::Size& size, | |
24 gfx::BufferFormat format, | |
25 gfx::BufferUsage usage, | |
26 gfx::GpuMemoryBufferHandle* handle, | |
27 bool* destroyed) { | |
28 return base::Bind(&GpuMemoryBufferImplTest::FreeGpuMemoryBuffer, | |
29 base::Unretained(this), | |
30 GpuMemoryBufferImplType::AllocateForTesting( | |
31 size, format, usage, handle), | |
32 base::Unretained(destroyed)); | |
33 } | |
34 | |
35 private: | |
36 void FreeGpuMemoryBuffer(const base::Closure& free_callback, | |
37 bool* destroyed, | |
38 const gpu::SyncToken& sync_token) { | |
39 free_callback.Run(); | |
40 if (destroyed) | |
41 *destroyed = true; | |
42 } | |
43 }; | |
44 | |
45 TYPED_TEST_CASE_P(GpuMemoryBufferImplTest); | |
46 | |
47 TYPED_TEST_P(GpuMemoryBufferImplTest, CreateFromHandle) { | |
48 const gfx::Size kBufferSize(8, 8); | |
49 | |
50 for (auto format : gfx::GetBufferFormatsForTesting()) { | |
51 gfx::BufferUsage usages[] = { | |
52 gfx::BufferUsage::GPU_READ, gfx::BufferUsage::SCANOUT, | |
53 gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, | |
54 gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT}; | |
55 for (auto usage : usages) { | |
56 if (!TypeParam::IsConfigurationSupported(format, usage)) | |
57 continue; | |
58 | |
59 bool destroyed = false; | |
60 gfx::GpuMemoryBufferHandle handle; | |
61 GpuMemoryBufferImpl::DestructionCallback destroy_callback = | |
62 TestFixture::AllocateGpuMemoryBuffer(kBufferSize, format, usage, | |
63 &handle, &destroyed); | |
64 scoped_ptr<TypeParam> buffer(TypeParam::CreateFromHandle( | |
65 handle, kBufferSize, format, usage, destroy_callback)); | |
66 ASSERT_TRUE(buffer); | |
67 EXPECT_EQ(buffer->GetFormat(), format); | |
68 | |
69 // Check if destruction callback is executed when deleting the buffer. | |
70 buffer.reset(); | |
71 ASSERT_TRUE(destroyed); | |
72 } | |
73 } | |
74 } | |
75 | |
76 TYPED_TEST_P(GpuMemoryBufferImplTest, Map) { | |
77 // Use a multiple of 4 for both dimensions to support compressed formats. | |
78 const gfx::Size kBufferSize(4, 4); | |
79 | |
80 for (auto format : gfx::GetBufferFormatsForTesting()) { | |
81 if (!TypeParam::IsConfigurationSupported( | |
82 format, gfx::BufferUsage::GPU_READ_CPU_READ_WRITE)) { | |
83 continue; | |
84 } | |
85 | |
86 gfx::GpuMemoryBufferHandle handle; | |
87 GpuMemoryBufferImpl::DestructionCallback destroy_callback = | |
88 TestFixture::AllocateGpuMemoryBuffer( | |
89 kBufferSize, format, gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, | |
90 &handle, nullptr); | |
91 scoped_ptr<TypeParam> buffer(TypeParam::CreateFromHandle( | |
92 handle, kBufferSize, format, gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, | |
93 destroy_callback)); | |
94 ASSERT_TRUE(buffer); | |
95 | |
96 const size_t num_planes = gfx::NumberOfPlanesForBufferFormat(format); | |
97 | |
98 // Map buffer into user space. | |
99 ASSERT_TRUE(buffer->Map()); | |
100 | |
101 // Copy and compare mapped buffers. | |
102 for (size_t plane = 0; plane < num_planes; ++plane) { | |
103 const size_t row_size_in_bytes = | |
104 gfx::RowSizeForBufferFormat(kBufferSize.width(), format, plane); | |
105 EXPECT_GT(row_size_in_bytes, 0u); | |
106 | |
107 scoped_ptr<char[]> data(new char[row_size_in_bytes]); | |
108 memset(data.get(), 0x2a + plane, row_size_in_bytes); | |
109 | |
110 size_t height = kBufferSize.height() / | |
111 gfx::SubsamplingFactorForBufferFormat(format, plane); | |
112 for (size_t y = 0; y < height; ++y) { | |
113 memcpy(static_cast<char*>(buffer->memory(plane)) + | |
114 y * buffer->stride(plane), | |
115 data.get(), row_size_in_bytes); | |
116 EXPECT_EQ(0, memcmp(static_cast<char*>(buffer->memory(plane)) + | |
117 y * buffer->stride(plane), | |
118 data.get(), row_size_in_bytes)); | |
119 } | |
120 } | |
121 | |
122 buffer->Unmap(); | |
123 } | |
124 } | |
125 | |
126 TYPED_TEST_P(GpuMemoryBufferImplTest, PersistentMap) { | |
127 // Use a multiple of 4 for both dimensions to support compressed formats. | |
128 const gfx::Size kBufferSize(4, 4); | |
129 | |
130 for (auto format : gfx::GetBufferFormatsForTesting()) { | |
131 if (!TypeParam::IsConfigurationSupported( | |
132 format, gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT)) { | |
133 continue; | |
134 } | |
135 | |
136 gfx::GpuMemoryBufferHandle handle; | |
137 GpuMemoryBufferImpl::DestructionCallback destroy_callback = | |
138 TestFixture::AllocateGpuMemoryBuffer( | |
139 kBufferSize, format, | |
140 gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT, &handle, | |
141 nullptr); | |
142 scoped_ptr<TypeParam> buffer(TypeParam::CreateFromHandle( | |
143 handle, kBufferSize, format, | |
144 gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT, | |
145 destroy_callback)); | |
146 ASSERT_TRUE(buffer); | |
147 | |
148 // Map buffer into user space. | |
149 ASSERT_TRUE(buffer->Map()); | |
150 | |
151 // Copy and compare mapped buffers. | |
152 size_t num_planes = gfx::NumberOfPlanesForBufferFormat(format); | |
153 for (size_t plane = 0; plane < num_planes; ++plane) { | |
154 const size_t row_size_in_bytes = | |
155 gfx::RowSizeForBufferFormat(kBufferSize.width(), format, plane); | |
156 EXPECT_GT(row_size_in_bytes, 0u); | |
157 | |
158 scoped_ptr<char[]> data(new char[row_size_in_bytes]); | |
159 memset(data.get(), 0x2a + plane, row_size_in_bytes); | |
160 | |
161 size_t height = kBufferSize.height() / | |
162 gfx::SubsamplingFactorForBufferFormat(format, plane); | |
163 for (size_t y = 0; y < height; ++y) { | |
164 memcpy(static_cast<char*>(buffer->memory(plane)) + | |
165 y * buffer->stride(plane), | |
166 data.get(), row_size_in_bytes); | |
167 EXPECT_EQ(0, memcmp(static_cast<char*>(buffer->memory(plane)) + | |
168 y * buffer->stride(plane), | |
169 data.get(), row_size_in_bytes)); | |
170 } | |
171 } | |
172 | |
173 buffer->Unmap(); | |
174 | |
175 // Remap the buffer, and compare again. It should contain the same data. | |
176 ASSERT_TRUE(buffer->Map()); | |
177 | |
178 for (size_t plane = 0; plane < num_planes; ++plane) { | |
179 const size_t row_size_in_bytes = | |
180 gfx::RowSizeForBufferFormat(kBufferSize.width(), format, plane); | |
181 | |
182 scoped_ptr<char[]> data(new char[row_size_in_bytes]); | |
183 memset(data.get(), 0x2a + plane, row_size_in_bytes); | |
184 | |
185 size_t height = kBufferSize.height() / | |
186 gfx::SubsamplingFactorForBufferFormat(format, plane); | |
187 for (size_t y = 0; y < height; ++y) { | |
188 EXPECT_EQ(0, memcmp(static_cast<char*>(buffer->memory(plane)) + | |
189 y * buffer->stride(plane), | |
190 data.get(), row_size_in_bytes)); | |
191 } | |
192 } | |
193 | |
194 buffer->Unmap(); | |
195 } | |
196 } | |
197 | |
198 // The GpuMemoryBufferImplTest test case verifies behavior that is expected | |
199 // from a GpuMemoryBuffer implementation in order to be conformant. | |
200 REGISTER_TYPED_TEST_CASE_P(GpuMemoryBufferImplTest, | |
201 CreateFromHandle, | |
202 Map, | |
203 PersistentMap); | |
204 | |
205 } // namespace content | |
206 | |
207 #endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_TEST_TEMPLATE_H_ | |
OLD | NEW |