OLD | NEW |
| (Empty) |
1 // Copyright 2017 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 "components/viz/common/server_gpu_memory_buffer_manager.h" | |
6 | |
7 #include "base/test/scoped_task_environment.h" | |
8 #include "gpu/ipc/host/gpu_memory_buffer_support.h" | |
9 #include "services/ui/gpu/interfaces/gpu_service.mojom.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 #include "ui/gfx/client_native_pixmap_factory.h" | |
12 | |
13 namespace viz { | |
14 | |
15 namespace { | |
16 | |
17 class TestGpuService : public ui::mojom::GpuService { | |
18 public: | |
19 TestGpuService() {} | |
20 ~TestGpuService() override {} | |
21 | |
22 bool HasAllocationRequest(gfx::GpuMemoryBufferId id, int client_id) const { | |
23 for (const auto& req : allocation_requests_) { | |
24 if (req.id == id && req.client_id == client_id) | |
25 return true; | |
26 } | |
27 return false; | |
28 } | |
29 | |
30 bool HasDestructionRequest(gfx::GpuMemoryBufferId id, int client_id) const { | |
31 for (const auto& req : destruction_requests_) { | |
32 if (req.id == id && req.client_id == client_id) | |
33 return true; | |
34 } | |
35 return false; | |
36 } | |
37 | |
38 void SatisfyAllocationRequest(gfx::GpuMemoryBufferId id, int client_id) { | |
39 for (const auto& req : allocation_requests_) { | |
40 if (req.id == id && req.client_id == client_id) { | |
41 gfx::GpuMemoryBufferHandle handle; | |
42 handle.id = id; | |
43 handle.type = gfx::SHARED_MEMORY_BUFFER; | |
44 req.callback.Run(handle); | |
45 return; | |
46 } | |
47 } | |
48 NOTREACHED(); | |
49 } | |
50 | |
51 // ui::mojom::GpuService: | |
52 void EstablishGpuChannel( | |
53 int32_t client_id, | |
54 uint64_t client_tracing_id, | |
55 bool is_gpu_host, | |
56 const EstablishGpuChannelCallback& callback) override {} | |
57 | |
58 void CloseChannel(int32_t client_id) override {} | |
59 | |
60 void CreateGpuMemoryBuffer( | |
61 gfx::GpuMemoryBufferId id, | |
62 const gfx::Size& size, | |
63 gfx::BufferFormat format, | |
64 gfx::BufferUsage usage, | |
65 int client_id, | |
66 gpu::SurfaceHandle surface_handle, | |
67 const CreateGpuMemoryBufferCallback& callback) override { | |
68 allocation_requests_.push_back( | |
69 {id, size, format, usage, client_id, callback}); | |
70 } | |
71 | |
72 void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id, | |
73 int client_id, | |
74 const gpu::SyncToken& sync_token) override { | |
75 destruction_requests_.push_back({id, client_id}); | |
76 } | |
77 | |
78 void GetVideoMemoryUsageStats( | |
79 const GetVideoMemoryUsageStatsCallback& callback) override {} | |
80 | |
81 void RequestCompleteGpuInfo( | |
82 const RequestCompleteGpuInfoCallback& callback) override {} | |
83 | |
84 void LoadedShader(const std::string& data) override {} | |
85 | |
86 void DestroyingVideoSurface( | |
87 int32_t surface_id, | |
88 const DestroyingVideoSurfaceCallback& callback) override {} | |
89 | |
90 void WakeUpGpu() override {} | |
91 | |
92 void GpuSwitched() override {} | |
93 | |
94 void DestroyAllChannels() override {} | |
95 | |
96 void Crash() override {} | |
97 | |
98 void Hang() override {} | |
99 | |
100 void ThrowJavaException() override {} | |
101 | |
102 void Stop(const StopCallback& callback) override {} | |
103 | |
104 private: | |
105 struct AllocationRequest { | |
106 const gfx::GpuMemoryBufferId id; | |
107 const gfx::Size size; | |
108 const gfx::BufferFormat format; | |
109 const gfx::BufferUsage usage; | |
110 const int client_id; | |
111 const CreateGpuMemoryBufferCallback callback; | |
112 }; | |
113 std::vector<AllocationRequest> allocation_requests_; | |
114 | |
115 struct DestructionRequest { | |
116 const gfx::GpuMemoryBufferId id; | |
117 const int client_id; | |
118 }; | |
119 std::vector<DestructionRequest> destruction_requests_; | |
120 | |
121 DISALLOW_COPY_AND_ASSIGN(TestGpuService); | |
122 }; | |
123 | |
124 // It is necessary to install a custom pixmap factory which claims to support | |
125 // all native configurations, so that code that deals with this can be tested | |
126 // correctly. | |
127 class FakeClientNativePixmapFactory : public gfx::ClientNativePixmapFactory { | |
128 public: | |
129 FakeClientNativePixmapFactory() {} | |
130 ~FakeClientNativePixmapFactory() override {} | |
131 | |
132 // gfx::ClientNativePixmapFactory: | |
133 bool IsConfigurationSupported(gfx::BufferFormat format, | |
134 gfx::BufferUsage usage) const override { | |
135 return true; | |
136 } | |
137 std::unique_ptr<gfx::ClientNativePixmap> ImportFromHandle( | |
138 const gfx::NativePixmapHandle& handle, | |
139 const gfx::Size& size, | |
140 gfx::BufferUsage usage) override { | |
141 NOTREACHED(); | |
142 return nullptr; | |
143 } | |
144 | |
145 private: | |
146 DISALLOW_COPY_AND_ASSIGN(FakeClientNativePixmapFactory); | |
147 }; | |
148 | |
149 } // namespace | |
150 | |
151 class ServerGpuMemoryBufferManagerTest : public ::testing::Test { | |
152 public: | |
153 ServerGpuMemoryBufferManagerTest() = default; | |
154 ~ServerGpuMemoryBufferManagerTest() override = default; | |
155 | |
156 // ::testing::Test: | |
157 void SetUp() override { | |
158 gfx::ClientNativePixmapFactory::ResetInstance(); | |
159 gfx::ClientNativePixmapFactory::SetInstance(&pixmap_factory_); | |
160 } | |
161 | |
162 void TearDown() override { gfx::ClientNativePixmapFactory::ResetInstance(); } | |
163 | |
164 private: | |
165 base::test::ScopedTaskEnvironment env_; | |
166 FakeClientNativePixmapFactory pixmap_factory_; | |
167 | |
168 DISALLOW_COPY_AND_ASSIGN(ServerGpuMemoryBufferManagerTest); | |
169 }; | |
170 | |
171 // Tests that allocation requests from a client that goes away before allocation | |
172 // completes are cleaned up correctly. | |
173 TEST_F(ServerGpuMemoryBufferManagerTest, AllocationRequestsForDestroyedClient) { | |
174 #if !defined(USE_OZONE) && !defined(OS_MACOSX) | |
175 // Not all platforms support native configurations (currently only ozone and | |
176 // mac support it). Abort the test in those platforms. | |
177 DCHECK(gpu::GetNativeGpuMemoryBufferConfigurations().empty()); | |
178 return; | |
179 #else | |
180 // Note: ServerGpuMemoryBufferManager normally operates on a mojom::GpuService | |
181 // implementation over mojo. Which means the communication from SGMBManager to | |
182 // GpuService is asynchronous. In this test, the mojom::GpuService is not | |
183 // bound to a mojo pipe, which means those calls are all synchronous. | |
184 TestGpuService gpu_service; | |
185 ServerGpuMemoryBufferManager manager(&gpu_service, 1); | |
186 | |
187 const auto buffer_id = static_cast<gfx::GpuMemoryBufferId>(1); | |
188 const int client_id = 2; | |
189 const gfx::Size size(10, 20); | |
190 const gfx::BufferFormat format = gfx::BufferFormat::RGBA_8888; | |
191 const gfx::BufferUsage usage = gfx::BufferUsage::GPU_READ; | |
192 manager.AllocateGpuMemoryBuffer( | |
193 buffer_id, client_id, size, format, usage, gpu::kNullSurfaceHandle, | |
194 base::BindOnce([](const gfx::GpuMemoryBufferHandle& handle) {})); | |
195 EXPECT_TRUE(gpu_service.HasAllocationRequest(buffer_id, client_id)); | |
196 EXPECT_FALSE(gpu_service.HasDestructionRequest(buffer_id, client_id)); | |
197 | |
198 // Destroy the client. Since no memory has been allocated yet, there will be | |
199 // no request for freeing memory. | |
200 manager.DestroyAllGpuMemoryBufferForClient(client_id); | |
201 EXPECT_TRUE(gpu_service.HasAllocationRequest(buffer_id, client_id)); | |
202 EXPECT_FALSE(gpu_service.HasDestructionRequest(buffer_id, client_id)); | |
203 | |
204 // When the host receives the allocated memory for the destroyed client, it | |
205 // should request the allocated memory to be freed. | |
206 gpu_service.SatisfyAllocationRequest(buffer_id, client_id); | |
207 EXPECT_TRUE(gpu_service.HasDestructionRequest(buffer_id, client_id)); | |
208 #endif | |
209 } | |
210 | |
211 TEST_F(ServerGpuMemoryBufferManagerTest, | |
212 RequestsFromUntrustedClientsValidated) { | |
213 gfx::ClientNativePixmapFactory::ResetInstance(); | |
214 TestGpuService gpu_service; | |
215 ServerGpuMemoryBufferManager manager(&gpu_service, 1); | |
216 const auto buffer_id = static_cast<gfx::GpuMemoryBufferId>(1); | |
217 const int client_id = 2; | |
218 // SCANOUT cannot be used if native gpu memory buffer is not supported. | |
219 // When ATC is used, both width and height should be multiples of 4. | |
220 struct { | |
221 gfx::BufferUsage usage; | |
222 gfx::BufferFormat format; | |
223 gfx::Size size; | |
224 bool expect_null_handle; | |
225 } configs[] = { | |
226 {gfx::BufferUsage::SCANOUT, gfx::BufferFormat::YVU_420, {10, 20}, true}, | |
227 {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::ATC, {10, 20}, true}, | |
228 {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::YVU_420, {10, 20}, false}, | |
229 }; | |
230 for (const auto& config : configs) { | |
231 gfx::GpuMemoryBufferHandle allocated_handle; | |
232 base::RunLoop runloop; | |
233 manager.AllocateGpuMemoryBuffer( | |
234 buffer_id, client_id, config.size, config.format, config.usage, | |
235 gpu::kNullSurfaceHandle, | |
236 base::BindOnce( | |
237 [](gfx::GpuMemoryBufferHandle* allocated_handle, | |
238 const base::Closure& callback, | |
239 const gfx::GpuMemoryBufferHandle& handle) { | |
240 *allocated_handle = handle; | |
241 callback.Run(); | |
242 }, | |
243 &allocated_handle, runloop.QuitClosure())); | |
244 // Since native gpu memory buffers are not supported, the mojom.GpuService | |
245 // should not receive any allocation requests. | |
246 EXPECT_FALSE(gpu_service.HasAllocationRequest(buffer_id, client_id)); | |
247 runloop.Run(); | |
248 if (config.expect_null_handle) { | |
249 EXPECT_TRUE(allocated_handle.is_null()); | |
250 } else { | |
251 EXPECT_FALSE(allocated_handle.is_null()); | |
252 EXPECT_EQ(gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER, | |
253 allocated_handle.type); | |
254 } | |
255 } | |
256 } | |
257 | |
258 } // namespace viz | |
OLD | NEW |