Fix broken path in extensions/common/PRESUBMIT.py
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_memory_buffer_manager.cc
blob70184a0f48aeb2218554e36f37314ed2ba6854ac
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/strings/stringprintf.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "base/trace_event/process_memory_dump.h"
13 #include "base/trace_event/trace_event.h"
14 #include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
15 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
16 #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
17 #include "content/public/browser/browser_thread.h"
19 namespace content {
20 namespace {
22 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
24 // Global atomic to generate gpu memory buffer unique IDs.
25 base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id;
27 const char kMemoryAllocatorName[] = "gpumemorybuffer";
29 } // namespace
31 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest {
32 AllocateGpuMemoryBufferRequest(const gfx::Size& size,
33 gfx::GpuMemoryBuffer::Format format,
34 gfx::GpuMemoryBuffer::Usage usage,
35 int client_id,
36 int surface_id)
37 : event(true, false),
38 size(size),
39 format(format),
40 usage(usage),
41 client_id(client_id),
42 surface_id(surface_id) {}
43 ~AllocateGpuMemoryBufferRequest() {}
44 base::WaitableEvent event;
45 gfx::Size size;
46 gfx::GpuMemoryBuffer::Format format;
47 gfx::GpuMemoryBuffer::Usage usage;
48 int client_id;
49 int surface_id;
50 scoped_ptr<gfx::GpuMemoryBuffer> result;
53 BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(
54 GpuMemoryBufferFactoryHost* gpu_memory_buffer_factory_host,
55 int gpu_client_id)
56 : gpu_memory_buffer_factory_host_(gpu_memory_buffer_factory_host),
57 gpu_client_id_(gpu_client_id),
58 weak_ptr_factory_(this) {
59 DCHECK(!g_gpu_memory_buffer_manager);
60 g_gpu_memory_buffer_manager = this;
63 BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() {
64 g_gpu_memory_buffer_manager = nullptr;
67 // static
68 BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() {
69 return g_gpu_memory_buffer_manager;
72 scoped_ptr<gfx::GpuMemoryBuffer>
73 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
74 const gfx::Size& size,
75 gfx::GpuMemoryBuffer::Format format,
76 gfx::GpuMemoryBuffer::Usage usage) {
77 return AllocateGpuMemoryBufferCommon(size, format, usage, 0);
80 scoped_ptr<gfx::GpuMemoryBuffer>
81 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout(
82 const gfx::Size& size,
83 gfx::GpuMemoryBuffer::Format format,
84 int32 surface_id) {
85 DCHECK_GT(surface_id, 0);
86 return AllocateGpuMemoryBufferCommon(
87 size, format, gfx::GpuMemoryBuffer::SCANOUT, surface_id);
90 scoped_ptr<gfx::GpuMemoryBuffer>
91 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferCommon(
92 const gfx::Size& size,
93 gfx::GpuMemoryBuffer::Format format,
94 gfx::GpuMemoryBuffer::Usage usage,
95 int32 surface_id) {
96 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
98 // Fallback to shared memory buffer if |format| and |usage| are not supported
99 // by factory.
100 if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
101 format, usage)) {
102 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(format));
103 DCHECK_EQ(usage, gfx::GpuMemoryBuffer::MAP);
104 return GpuMemoryBufferImplSharedMemory::Create(
105 g_next_gpu_memory_buffer_id.GetNext(), size, format);
108 AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_,
109 surface_id);
110 BrowserThread::PostTask(
111 BrowserThread::IO,
112 FROM_HERE,
113 base::Bind(&BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO,
114 base::Unretained(this), // Safe as we wait for result below.
115 base::Unretained(&request)));
117 // We're blocking the UI thread, which is generally undesirable.
118 TRACE_EVENT0("browser",
119 "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer");
120 base::ThreadRestrictions::ScopedAllowWait allow_wait;
121 request.event.Wait();
122 return request.result.Pass();
125 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
126 const gfx::Size& size,
127 gfx::GpuMemoryBuffer::Format format,
128 gfx::GpuMemoryBuffer::Usage usage,
129 base::ProcessHandle child_process_handle,
130 int child_client_id,
131 const AllocationCallback& callback) {
132 DCHECK_CURRENTLY_ON(BrowserThread::IO);
134 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext();
136 BufferMap& buffers = clients_[child_client_id];
137 DCHECK(buffers.find(new_id) == buffers.end());
139 // Fallback to shared memory buffer if |format| and |usage| are not supported
140 // by factory.
141 if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
142 format, usage)) {
143 // Early out if we cannot fallback to shared memory buffer.
144 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) ||
145 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format) ||
146 usage != gfx::GpuMemoryBuffer::MAP) {
147 callback.Run(gfx::GpuMemoryBufferHandle());
148 return;
151 buffers[new_id] = BufferInfo(size, format, gfx::SHARED_MEMORY_BUFFER);
152 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
153 new_id, size, format, child_process_handle));
154 return;
157 // Note: Handling of cases where the child process is removed before the
158 // allocation completes is less subtle if we set the buffer type to
159 // EMPTY_BUFFER here and verify that this has not changed when allocation
160 // completes.
161 buffers[new_id] = BufferInfo(size, format, gfx::EMPTY_BUFFER);
163 gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
164 new_id, size, format, usage, child_client_id, 0,
165 base::Bind(&BrowserGpuMemoryBufferManager::
166 GpuMemoryBufferAllocatedForChildProcess,
167 weak_ptr_factory_.GetWeakPtr(), child_client_id, callback));
170 gfx::GpuMemoryBuffer*
171 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
172 ClientBuffer buffer) {
173 return GpuMemoryBufferImpl::FromClientBuffer(buffer);
176 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint(
177 gfx::GpuMemoryBuffer* buffer,
178 uint32 sync_point) {
179 static_cast<GpuMemoryBufferImpl*>(buffer)
180 ->set_destruction_sync_point(sync_point);
183 bool BrowserGpuMemoryBufferManager::OnMemoryDump(
184 base::trace_event::ProcessMemoryDump* pmd) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO);
187 for (const auto& client : clients_) {
188 for (const auto& buffer : client.second) {
189 if (buffer.second.type == gfx::EMPTY_BUFFER)
190 continue;
192 base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
193 base::StringPrintf("%s/%d", kMemoryAllocatorName, buffer.first));
194 if (!dump)
195 return false;
197 size_t buffer_size_in_bytes = 0;
198 // Note: BufferSizeInBytes returns an approximated size for the buffer
199 // but the factory can be made to return the exact size if this
200 // approximation is not good enough.
201 bool valid_size = GpuMemoryBufferImpl::BufferSizeInBytes(
202 buffer.second.size, buffer.second.format, &buffer_size_in_bytes);
203 DCHECK(valid_size);
205 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameOuterSize,
206 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
207 buffer_size_in_bytes);
211 return true;
214 void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
215 gfx::GpuMemoryBufferId id,
216 base::ProcessHandle child_process_handle,
217 int child_client_id,
218 uint32 sync_point) {
219 DCHECK_CURRENTLY_ON(BrowserThread::IO);
220 DCHECK(clients_.find(child_client_id) != clients_.end());
222 BufferMap& buffers = clients_[child_client_id];
224 BufferMap::iterator buffer_it = buffers.find(id);
225 if (buffer_it == buffers.end()) {
226 LOG(ERROR) << "Invalid GpuMemoryBuffer ID for child process.";
227 return;
230 // This can happen if a child process managed to trigger a call to this while
231 // a buffer is in the process of being allocated.
232 if (buffer_it->second.type == gfx::EMPTY_BUFFER) {
233 LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
234 return;
237 // Buffers allocated using the factory need to be destroyed through the
238 // factory.
239 if (buffer_it->second.type != gfx::SHARED_MEMORY_BUFFER) {
240 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
241 child_client_id,
242 sync_point);
245 buffers.erase(buffer_it);
248 void BrowserGpuMemoryBufferManager::ProcessRemoved(
249 base::ProcessHandle process_handle,
250 int client_id) {
251 DCHECK_CURRENTLY_ON(BrowserThread::IO);
253 ClientMap::iterator client_it = clients_.find(client_id);
254 if (client_it == clients_.end())
255 return;
257 for (const auto& buffer : client_it->second) {
258 // This might happen if buffer is currenlty in the process of being
259 // allocated. The buffer will in that case be cleaned up when allocation
260 // completes.
261 if (buffer.second.type == gfx::EMPTY_BUFFER)
262 continue;
264 // Skip shared memory buffers as they were not allocated using the factory.
265 if (buffer.second.type == gfx::SHARED_MEMORY_BUFFER)
266 continue;
268 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(buffer.first,
269 client_id, 0);
272 clients_.erase(client_it);
275 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
276 AllocateGpuMemoryBufferRequest* request) {
277 // Note: Unretained is safe as this is only used for synchronous allocation
278 // from a non-IO thread.
279 gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
280 g_next_gpu_memory_buffer_id.GetNext(), request->size, request->format,
281 request->usage, request->client_id, request->surface_id,
282 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO,
283 base::Unretained(this), base::Unretained(request)));
286 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
287 AllocateGpuMemoryBufferRequest* request,
288 const gfx::GpuMemoryBufferHandle& handle) {
289 DCHECK_CURRENTLY_ON(BrowserThread::IO);
291 // Early out if factory failed to allocate the buffer.
292 if (handle.is_null()) {
293 request->event.Signal();
294 return;
297 DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
298 request->result = GpuMemoryBufferImpl::CreateFromHandle(
299 handle,
300 request->size,
301 request->format,
302 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted,
303 weak_ptr_factory_.GetWeakPtr(),
304 handle.id,
305 request->client_id));
306 request->event.Signal();
309 void BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted(
310 gfx::GpuMemoryBufferId id,
311 int client_id,
312 uint32 sync_point) {
313 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
314 client_id,
315 sync_point);
318 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
319 int child_client_id,
320 const AllocationCallback& callback,
321 const gfx::GpuMemoryBufferHandle& handle) {
322 DCHECK_CURRENTLY_ON(BrowserThread::IO);
324 ClientMap::iterator client_it = clients_.find(child_client_id);
326 // This can happen if the child process is removed while the buffer is being
327 // allocated.
328 if (client_it == clients_.end()) {
329 if (!handle.is_null()) {
330 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(
331 handle.id, child_client_id, 0);
333 callback.Run(gfx::GpuMemoryBufferHandle());
334 return;
337 BufferMap& buffers = client_it->second;
339 BufferMap::iterator buffer_it = buffers.find(handle.id);
340 DCHECK(buffer_it != buffers.end());
341 DCHECK_EQ(buffer_it->second.type, gfx::EMPTY_BUFFER);
343 if (handle.is_null()) {
344 buffers.erase(buffer_it);
345 callback.Run(gfx::GpuMemoryBufferHandle());
346 return;
349 // The factory should never return a shared memory backed buffer.
350 DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
352 // Store the type of this buffer so it can be cleaned up if the child
353 // process is removed.
354 buffer_it->second.type = handle.type;
356 callback.Run(handle);
359 } // namespace content