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"
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"
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
;
28 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest
{
29 AllocateGpuMemoryBufferRequest(const gfx::Size
& size
,
30 gfx::GpuMemoryBuffer::Format format
,
31 gfx::GpuMemoryBuffer::Usage usage
,
39 surface_id(surface_id
) {}
40 ~AllocateGpuMemoryBufferRequest() {}
41 base::WaitableEvent event
;
43 gfx::GpuMemoryBuffer::Format format
;
44 gfx::GpuMemoryBuffer::Usage usage
;
47 scoped_ptr
<gfx::GpuMemoryBuffer
> result
;
50 BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(
51 GpuMemoryBufferFactoryHost
* gpu_memory_buffer_factory_host
,
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;
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
,
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
,
93 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO
));
95 // Fallback to shared memory buffer if |format| and |usage| are not supported
97 if (!gpu_memory_buffer_factory_host_
->IsGpuMemoryBufferConfigurationSupported(
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_
,
107 BrowserThread::PostTask(
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
,
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
138 if (!gpu_memory_buffer_factory_host_
->IsGpuMemoryBufferConfigurationSupported(
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());
147 buffers
[new_id
] = gfx::SHARED_MEMORY_BUFFER
;
148 callback
.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
149 new_id
, size
, format
, child_process_handle
));
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
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
,
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
,
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.";
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.";
202 // Buffers allocated using the factory need to be destroyed through the
204 if (buffer_it
->second
!= gfx::SHARED_MEMORY_BUFFER
) {
205 gpu_memory_buffer_factory_host_
->DestroyGpuMemoryBuffer(id
,
210 buffers
.erase(buffer_it
);
213 void BrowserGpuMemoryBufferManager::ProcessRemoved(
214 base::ProcessHandle process_handle
,
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
218 ClientMap::iterator client_it
= clients_
.find(client_id
);
219 if (client_it
== clients_
.end())
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
226 if (buffer_it
.second
== gfx::EMPTY_BUFFER
)
229 // Skip shared memory buffers as they were not allocated using the factory.
230 if (buffer_it
.second
== gfx::SHARED_MEMORY_BUFFER
)
233 gpu_memory_buffer_factory_host_
->DestroyGpuMemoryBuffer(buffer_it
.first
,
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();
263 DCHECK_NE(handle
.type
, gfx::SHARED_MEMORY_BUFFER
);
264 request
->result
= GpuMemoryBufferImpl::CreateFromHandle(
268 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted
,
269 weak_ptr_factory_
.GetWeakPtr(),
271 request
->client_id
));
272 request
->event
.Signal();
275 void BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted(
276 gfx::GpuMemoryBufferId id
,
279 gpu_memory_buffer_factory_host_
->DestroyGpuMemoryBuffer(id
,
284 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
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
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());
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());
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