Add remoting and PPAPI tests to GN build
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_memory_buffer_manager.cc
blob57c65fbe566d1fa1b1d1a47273e28bc0f0938ffd
1 // Copyright 2014 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/browser/gpu/browser_gpu_memory_buffer_manager.h"
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/lazy_instance.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "base/trace_event/trace_event.h"
13 #include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
14 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
15 #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
16 #include "content/public/browser/browser_thread.h"
18 namespace content {
19 namespace {
21 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
23 // Global atomic to generate gpu memory buffer unique IDs.
24 base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id;
26 } // namespace
28 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest {
29 AllocateGpuMemoryBufferRequest(const gfx::Size& size,
30 gfx::GpuMemoryBuffer::Format format,
31 gfx::GpuMemoryBuffer::Usage usage,
32 int client_id,
33 int surface_id)
34 : event(true, false),
35 size(size),
36 format(format),
37 usage(usage),
38 client_id(client_id),
39 surface_id(surface_id) {}
40 ~AllocateGpuMemoryBufferRequest() {}
41 base::WaitableEvent event;
42 gfx::Size size;
43 gfx::GpuMemoryBuffer::Format format;
44 gfx::GpuMemoryBuffer::Usage usage;
45 int client_id;
46 int surface_id;
47 scoped_ptr<gfx::GpuMemoryBuffer> result;
50 BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(
51 GpuMemoryBufferFactoryHost* gpu_memory_buffer_factory_host,
52 int gpu_client_id)
53 : gpu_memory_buffer_factory_host_(gpu_memory_buffer_factory_host),
54 gpu_client_id_(gpu_client_id),
55 weak_ptr_factory_(this) {
56 DCHECK(!g_gpu_memory_buffer_manager);
57 g_gpu_memory_buffer_manager = this;
60 BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() {
61 g_gpu_memory_buffer_manager = nullptr;
64 // static
65 BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() {
66 return g_gpu_memory_buffer_manager;
69 scoped_ptr<gfx::GpuMemoryBuffer>
70 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
71 const gfx::Size& size,
72 gfx::GpuMemoryBuffer::Format format,
73 gfx::GpuMemoryBuffer::Usage usage) {
74 return AllocateGpuMemoryBufferCommon(size, format, usage, 0);
77 scoped_ptr<gfx::GpuMemoryBuffer>
78 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout(
79 const gfx::Size& size,
80 gfx::GpuMemoryBuffer::Format format,
81 int32 surface_id) {
82 DCHECK_GT(surface_id, 0);
83 return AllocateGpuMemoryBufferCommon(
84 size, format, gfx::GpuMemoryBuffer::SCANOUT, surface_id);
87 scoped_ptr<gfx::GpuMemoryBuffer>
88 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferCommon(
89 const gfx::Size& size,
90 gfx::GpuMemoryBuffer::Format format,
91 gfx::GpuMemoryBuffer::Usage usage,
92 int32 surface_id) {
93 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
95 // Fallback to shared memory buffer if |format| and |usage| are not supported
96 // by factory.
97 if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
98 format, usage)) {
99 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(format));
100 DCHECK_EQ(usage, gfx::GpuMemoryBuffer::MAP);
101 return GpuMemoryBufferImplSharedMemory::Create(
102 g_next_gpu_memory_buffer_id.GetNext(), size, format);
105 AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_,
106 surface_id);
107 BrowserThread::PostTask(
108 BrowserThread::IO,
109 FROM_HERE,
110 base::Bind(&BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO,
111 base::Unretained(this), // Safe as we wait for result below.
112 base::Unretained(&request)));
114 // We're blocking the UI thread, which is generally undesirable.
115 TRACE_EVENT0("browser",
116 "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer");
117 base::ThreadRestrictions::ScopedAllowWait allow_wait;
118 request.event.Wait();
119 return request.result.Pass();
122 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
123 const gfx::Size& size,
124 gfx::GpuMemoryBuffer::Format format,
125 gfx::GpuMemoryBuffer::Usage usage,
126 base::ProcessHandle child_process_handle,
127 int child_client_id,
128 const AllocationCallback& callback) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext();
133 BufferMap& buffers = clients_[child_client_id];
134 DCHECK(buffers.find(new_id) == buffers.end());
136 // Fallback to shared memory buffer if |format| and |usage| are not supported
137 // by factory.
138 if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
139 format, usage)) {
140 // Early out if we cannot fallback to shared memory buffer.
141 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) ||
142 usage != gfx::GpuMemoryBuffer::MAP) {
143 callback.Run(gfx::GpuMemoryBufferHandle());
144 return;
147 buffers[new_id] = gfx::SHARED_MEMORY_BUFFER;
148 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
149 new_id, size, format, child_process_handle));
150 return;
153 // Note: Handling of cases where the child process is removed before the
154 // allocation completes is less subtle if we set the buffer type to
155 // EMPTY_BUFFER here and verify that this has not changed when allocation
156 // completes.
157 buffers[new_id] = gfx::EMPTY_BUFFER;
159 gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
160 new_id, size, format, usage, child_client_id, 0,
161 base::Bind(&BrowserGpuMemoryBufferManager::
162 GpuMemoryBufferAllocatedForChildProcess,
163 weak_ptr_factory_.GetWeakPtr(), child_client_id, callback));
166 gfx::GpuMemoryBuffer*
167 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
168 ClientBuffer buffer) {
169 return GpuMemoryBufferImpl::FromClientBuffer(buffer);
172 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint(
173 gfx::GpuMemoryBuffer* buffer,
174 uint32 sync_point) {
175 static_cast<GpuMemoryBufferImpl*>(buffer)
176 ->set_destruction_sync_point(sync_point);
179 void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
180 gfx::GpuMemoryBufferId id,
181 base::ProcessHandle child_process_handle,
182 int child_client_id,
183 uint32 sync_point) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
185 DCHECK(clients_.find(child_client_id) != clients_.end());
187 BufferMap& buffers = clients_[child_client_id];
189 BufferMap::iterator buffer_it = buffers.find(id);
190 if (buffer_it == buffers.end()) {
191 LOG(ERROR) << "Invalid GpuMemoryBuffer ID for child process.";
192 return;
195 // This can happen if a child process managed to trigger a call to this while
196 // a buffer is in the process of being allocated.
197 if (buffer_it->second == gfx::EMPTY_BUFFER) {
198 LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
199 return;
202 // Buffers allocated using the factory need to be destroyed through the
203 // factory.
204 if (buffer_it->second != gfx::SHARED_MEMORY_BUFFER) {
205 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
206 child_client_id,
207 sync_point);
210 buffers.erase(buffer_it);
213 void BrowserGpuMemoryBufferManager::ProcessRemoved(
214 base::ProcessHandle process_handle,
215 int client_id) {
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
218 ClientMap::iterator client_it = clients_.find(client_id);
219 if (client_it == clients_.end())
220 return;
222 for (auto &buffer_it : client_it->second) {
223 // This might happen if buffer is currenlty in the process of being
224 // allocated. The buffer will in that case be cleaned up when allocation
225 // completes.
226 if (buffer_it.second == gfx::EMPTY_BUFFER)
227 continue;
229 // Skip shared memory buffers as they were not allocated using the factory.
230 if (buffer_it.second == gfx::SHARED_MEMORY_BUFFER)
231 continue;
233 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(buffer_it.first,
234 client_id,
238 clients_.erase(client_it);
241 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
242 AllocateGpuMemoryBufferRequest* request) {
243 // Note: Unretained is safe as this is only used for synchronous allocation
244 // from a non-IO thread.
245 gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
246 g_next_gpu_memory_buffer_id.GetNext(), request->size, request->format,
247 request->usage, request->client_id, request->surface_id,
248 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO,
249 base::Unretained(this), base::Unretained(request)));
252 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
253 AllocateGpuMemoryBufferRequest* request,
254 const gfx::GpuMemoryBufferHandle& handle) {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
257 // Early out if factory failed to allocate the buffer.
258 if (handle.is_null()) {
259 request->event.Signal();
260 return;
263 DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
264 request->result = GpuMemoryBufferImpl::CreateFromHandle(
265 handle,
266 request->size,
267 request->format,
268 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted,
269 weak_ptr_factory_.GetWeakPtr(),
270 handle.id,
271 request->client_id));
272 request->event.Signal();
275 void BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted(
276 gfx::GpuMemoryBufferId id,
277 int client_id,
278 uint32 sync_point) {
279 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
280 client_id,
281 sync_point);
284 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
285 int child_client_id,
286 const AllocationCallback& callback,
287 const gfx::GpuMemoryBufferHandle& handle) {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
290 ClientMap::iterator client_it = clients_.find(child_client_id);
292 // This can happen if the child process is removed while the buffer is being
293 // allocated.
294 if (client_it == clients_.end()) {
295 if (!handle.is_null()) {
296 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(
297 handle.id, child_client_id, 0);
299 callback.Run(gfx::GpuMemoryBufferHandle());
300 return;
303 BufferMap& buffers = client_it->second;
305 BufferMap::iterator buffer_it = buffers.find(handle.id);
306 DCHECK(buffer_it != buffers.end());
307 DCHECK_EQ(buffer_it->second, gfx::EMPTY_BUFFER);
309 if (handle.is_null()) {
310 buffers.erase(buffer_it);
311 callback.Run(gfx::GpuMemoryBufferHandle());
312 return;
315 // The factory should never return a shared memory backed buffer.
316 DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
318 // Store the type of this buffer so it can be cleaned up if the child
319 // process is removed.
320 buffer_it->second = handle.type;
322 callback.Run(handle);
325 } // namespace content