Process Alt-Svc headers.
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_memory_buffer_manager.cc
blob21c81ca1424050eb251aa33f19480bbe3438d052
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/command_line.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "base/trace_event/process_memory_dump.h"
14 #include "base/trace_event/trace_event.h"
15 #include "content/browser/gpu/gpu_process_host.h"
16 #include "content/common/child_process_host_impl.h"
17 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
18 #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
19 #include "content/common/gpu/gpu_memory_buffer_factory_shared_memory.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/common/content_switches.h"
22 #include "gpu/GLES2/gl2extchromium.h"
24 #if defined(OS_MACOSX)
25 #include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
26 #endif
28 #if defined(OS_ANDROID)
29 #include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
30 #endif
32 #if defined(USE_OZONE)
33 #include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h"
34 #endif
36 namespace content {
37 namespace {
39 void GpuMemoryBufferDeleted(
40 scoped_refptr<base::SingleThreadTaskRunner> destruction_task_runner,
41 const GpuMemoryBufferImpl::DestructionCallback& destruction_callback,
42 uint32 sync_point) {
43 destruction_task_runner->PostTask(
44 FROM_HERE, base::Bind(destruction_callback, sync_point));
47 bool IsGpuMemoryBufferFactoryConfigurationSupported(
48 gfx::GpuMemoryBufferType type,
49 const GpuMemoryBufferFactory::Configuration& configuration) {
50 switch (type) {
51 case gfx::SHARED_MEMORY_BUFFER:
52 return GpuMemoryBufferFactorySharedMemory::
53 IsGpuMemoryBufferConfigurationSupported(configuration.format,
54 configuration.usage);
55 #if defined(OS_MACOSX)
56 case gfx::IO_SURFACE_BUFFER:
57 return GpuMemoryBufferFactoryIOSurface::
58 IsGpuMemoryBufferConfigurationSupported(configuration.format,
59 configuration.usage);
60 #endif
61 #if defined(OS_ANDROID)
62 case gfx::SURFACE_TEXTURE_BUFFER:
63 return GpuMemoryBufferFactorySurfaceTexture::
64 IsGpuMemoryBufferConfigurationSupported(configuration.format,
65 configuration.usage);
66 #endif
67 #if defined(USE_OZONE)
68 case gfx::OZONE_NATIVE_PIXMAP:
69 return GpuMemoryBufferFactoryOzoneNativePixmap::
70 IsGpuMemoryBufferConfigurationSupported(configuration.format,
71 configuration.usage);
72 #endif
73 default:
74 NOTREACHED();
75 return false;
79 gfx::GpuMemoryBufferType GetGpuMemoryBufferFactoryType() {
80 std::vector<gfx::GpuMemoryBufferType> supported_types;
81 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
82 DCHECK(!supported_types.empty());
84 // The GPU service will always use the preferred type.
85 return supported_types[0];
88 std::vector<GpuMemoryBufferFactory::Configuration>
89 GetSupportedGpuMemoryBufferConfigurations(gfx::GpuMemoryBufferType type) {
90 std::vector<GpuMemoryBufferFactory::Configuration> configurations;
91 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
92 switches::kEnableNativeGpuMemoryBuffers)) {
93 const GpuMemoryBufferFactory::Configuration kNativeConfigurations[] = {
94 {gfx::GpuMemoryBuffer::R_8, gfx::GpuMemoryBuffer::MAP},
95 {gfx::GpuMemoryBuffer::R_8, gfx::GpuMemoryBuffer::PERSISTENT_MAP},
96 {gfx::GpuMemoryBuffer::RGBA_4444, gfx::GpuMemoryBuffer::MAP},
97 {gfx::GpuMemoryBuffer::RGBA_4444, gfx::GpuMemoryBuffer::PERSISTENT_MAP},
98 {gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::MAP},
99 {gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::PERSISTENT_MAP},
100 {gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::MAP},
101 {gfx::GpuMemoryBuffer::BGRA_8888,
102 gfx::GpuMemoryBuffer::PERSISTENT_MAP}};
103 for (auto& configuration : kNativeConfigurations) {
104 if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration))
105 configurations.push_back(configuration);
109 #if defined(USE_OZONE) || defined(OS_MACOSX)
110 const GpuMemoryBufferFactory::Configuration kScanoutConfigurations[] = {
111 {gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::SCANOUT},
112 {gfx::GpuMemoryBuffer::RGBX_8888, gfx::GpuMemoryBuffer::SCANOUT}};
113 for (auto& configuration : kScanoutConfigurations) {
114 if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration))
115 configurations.push_back(configuration);
117 #endif
119 return configurations;
122 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
124 // Global atomic to generate gpu memory buffer unique IDs.
125 base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id;
127 } // namespace
129 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest {
130 AllocateGpuMemoryBufferRequest(const gfx::Size& size,
131 gfx::GpuMemoryBuffer::Format format,
132 gfx::GpuMemoryBuffer::Usage usage,
133 int client_id,
134 int surface_id)
135 : event(true, false),
136 size(size),
137 format(format),
138 usage(usage),
139 client_id(client_id),
140 surface_id(surface_id) {}
141 ~AllocateGpuMemoryBufferRequest() {}
142 base::WaitableEvent event;
143 gfx::Size size;
144 gfx::GpuMemoryBuffer::Format format;
145 gfx::GpuMemoryBuffer::Usage usage;
146 int client_id;
147 int surface_id;
148 scoped_ptr<gfx::GpuMemoryBuffer> result;
151 BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(int gpu_client_id)
152 : factory_type_(GetGpuMemoryBufferFactoryType()),
153 supported_configurations_(
154 GetSupportedGpuMemoryBufferConfigurations(factory_type_)),
155 gpu_client_id_(gpu_client_id),
156 gpu_host_id_(0) {
157 DCHECK(!g_gpu_memory_buffer_manager);
158 g_gpu_memory_buffer_manager = this;
161 BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() {
162 g_gpu_memory_buffer_manager = nullptr;
165 // static
166 BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() {
167 return g_gpu_memory_buffer_manager;
170 // static
171 uint32 BrowserGpuMemoryBufferManager::GetImageTextureTarget(
172 gfx::GpuMemoryBuffer::Format format,
173 gfx::GpuMemoryBuffer::Usage usage) {
174 gfx::GpuMemoryBufferType type = GetGpuMemoryBufferFactoryType();
175 for (auto& configuration : GetSupportedGpuMemoryBufferConfigurations(type)) {
176 if (configuration.format != format || configuration.usage != usage)
177 continue;
179 switch (type) {
180 case gfx::SURFACE_TEXTURE_BUFFER:
181 case gfx::OZONE_NATIVE_PIXMAP:
182 // GPU memory buffers that are shared with the GL using EGLImages
183 // require TEXTURE_EXTERNAL_OES.
184 return GL_TEXTURE_EXTERNAL_OES;
185 case gfx::IO_SURFACE_BUFFER:
186 // IOSurface backed images require GL_TEXTURE_RECTANGLE_ARB.
187 return GL_TEXTURE_RECTANGLE_ARB;
188 default:
189 return GL_TEXTURE_2D;
193 return GL_TEXTURE_2D;
196 scoped_ptr<gfx::GpuMemoryBuffer>
197 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
198 const gfx::Size& size,
199 gfx::GpuMemoryBuffer::Format format,
200 gfx::GpuMemoryBuffer::Usage usage) {
201 return AllocateGpuMemoryBufferForSurface(size, format, usage, 0);
204 scoped_ptr<gfx::GpuMemoryBuffer>
205 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout(
206 const gfx::Size& size,
207 gfx::GpuMemoryBuffer::Format format,
208 int32 surface_id) {
209 DCHECK_GT(surface_id, 0);
210 return AllocateGpuMemoryBufferForSurface(
211 size, format, gfx::GpuMemoryBuffer::SCANOUT, surface_id);
214 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
215 const gfx::Size& size,
216 gfx::GpuMemoryBuffer::Format format,
217 gfx::GpuMemoryBuffer::Usage usage,
218 base::ProcessHandle child_process_handle,
219 int child_client_id,
220 const AllocationCallback& callback) {
221 DCHECK_CURRENTLY_ON(BrowserThread::IO);
223 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext();
225 // Use service side allocation if this is a supported configuration.
226 if (IsGpuMemoryBufferConfigurationSupported(format, usage)) {
227 AllocateGpuMemoryBufferOnIO(new_id, size, format, usage, child_client_id, 0,
228 false, callback);
229 return;
232 // Early out if we cannot fallback to shared memory buffer.
233 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) ||
234 !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) ||
235 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) {
236 callback.Run(gfx::GpuMemoryBufferHandle());
237 return;
240 BufferMap& buffers = clients_[child_client_id];
241 DCHECK(buffers.find(new_id) == buffers.end());
243 // Allocate shared memory buffer as fallback.
244 buffers[new_id] =
245 BufferInfo(size, gfx::SHARED_MEMORY_BUFFER, format, usage, 0);
246 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
247 new_id, size, format, child_process_handle));
250 gfx::GpuMemoryBuffer*
251 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
252 ClientBuffer buffer) {
253 return GpuMemoryBufferImpl::FromClientBuffer(buffer);
256 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint(
257 gfx::GpuMemoryBuffer* buffer,
258 uint32 sync_point) {
259 static_cast<GpuMemoryBufferImpl*>(buffer)
260 ->set_destruction_sync_point(sync_point);
263 bool BrowserGpuMemoryBufferManager::OnMemoryDump(
264 base::trace_event::ProcessMemoryDump* pmd) {
265 DCHECK_CURRENTLY_ON(BrowserThread::IO);
267 for (const auto& client : clients_) {
268 int client_id = client.first;
270 for (const auto& buffer : client.second) {
271 if (buffer.second.type == gfx::EMPTY_BUFFER)
272 continue;
274 gfx::GpuMemoryBufferId buffer_id = buffer.first;
275 base::trace_event::MemoryAllocatorDump* dump =
276 pmd->CreateAllocatorDump(base::StringPrintf(
277 "gpumemorybuffer/client_%d/buffer_%d", client_id, buffer_id));
278 if (!dump)
279 return false;
281 size_t buffer_size_in_bytes = 0;
282 // Note: BufferSizeInBytes returns an approximated size for the buffer
283 // but the factory can be made to return the exact size if this
284 // approximation is not good enough.
285 bool valid_size = GpuMemoryBufferImpl::BufferSizeInBytes(
286 buffer.second.size, buffer.second.format, &buffer_size_in_bytes);
287 DCHECK(valid_size);
289 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
290 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
291 buffer_size_in_bytes);
293 // Create the cross-process ownership edge. If the client creates a
294 // corresponding dump for the same buffer, this will avoid to
295 // double-count them in tracing. If, instead, no other process will emit a
296 // dump with the same guid, the segment will be accounted to the browser.
297 const uint64 client_tracing_process_id =
298 ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
299 client_id);
300 base::trace_event::MemoryAllocatorDumpGuid shared_buffer_guid =
301 gfx::GetGpuMemoryBufferGUIDForTracing(client_tracing_process_id,
302 buffer_id);
303 pmd->CreateSharedGlobalAllocatorDump(shared_buffer_guid);
304 pmd->AddOwnershipEdge(dump->guid(), shared_buffer_guid);
308 return true;
311 void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
312 gfx::GpuMemoryBufferId id,
313 base::ProcessHandle child_process_handle,
314 int child_client_id,
315 uint32 sync_point) {
316 DCHECK_CURRENTLY_ON(BrowserThread::IO);
318 DestroyGpuMemoryBufferOnIO(id, child_client_id, sync_point);
321 void BrowserGpuMemoryBufferManager::ProcessRemoved(
322 base::ProcessHandle process_handle,
323 int client_id) {
324 DCHECK_CURRENTLY_ON(BrowserThread::IO);
326 ClientMap::iterator client_it = clients_.find(client_id);
327 if (client_it == clients_.end())
328 return;
330 for (const auto& buffer : client_it->second) {
331 // This might happen if buffer is currenlty in the process of being
332 // allocated. The buffer will in that case be cleaned up when allocation
333 // completes.
334 if (buffer.second.type == gfx::EMPTY_BUFFER)
335 continue;
337 GpuProcessHost* host = GpuProcessHost::FromID(buffer.second.gpu_host_id);
338 if (host)
339 host->DestroyGpuMemoryBuffer(buffer.first, client_id, 0);
342 clients_.erase(client_it);
345 scoped_ptr<gfx::GpuMemoryBuffer>
346 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface(
347 const gfx::Size& size,
348 gfx::GpuMemoryBuffer::Format format,
349 gfx::GpuMemoryBuffer::Usage usage,
350 int32 surface_id) {
351 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
353 AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_,
354 surface_id);
355 BrowserThread::PostTask(
356 BrowserThread::IO, FROM_HERE,
357 base::Bind(
358 &BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO,
359 base::Unretained(this), // Safe as we wait for result below.
360 base::Unretained(&request)));
362 // We're blocking the UI thread, which is generally undesirable.
363 TRACE_EVENT0(
364 "browser",
365 "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface");
366 base::ThreadRestrictions::ScopedAllowWait allow_wait;
367 request.event.Wait();
368 return request.result.Pass();
371 bool BrowserGpuMemoryBufferManager::IsGpuMemoryBufferConfigurationSupported(
372 gfx::GpuMemoryBuffer::Format format,
373 gfx::GpuMemoryBuffer::Usage usage) const {
374 for (auto& configuration : supported_configurations_) {
375 if (configuration.format == format && configuration.usage == usage)
376 return true;
378 return false;
381 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO(
382 AllocateGpuMemoryBufferRequest* request) {
383 DCHECK_CURRENTLY_ON(BrowserThread::IO);
385 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext();
387 // Use service side allocation if this is a supported configuration.
388 if (IsGpuMemoryBufferConfigurationSupported(request->format,
389 request->usage)) {
390 // Note: Unretained is safe as this is only used for synchronous allocation
391 // from a non-IO thread.
392 AllocateGpuMemoryBufferOnIO(
393 new_id, request->size, request->format, request->usage,
394 request->client_id, request->surface_id, false,
395 base::Bind(&BrowserGpuMemoryBufferManager::
396 GpuMemoryBufferAllocatedForSurfaceOnIO,
397 base::Unretained(this), base::Unretained(request)));
398 return;
401 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(request->format))
402 << request->format;
403 DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage))
404 << request->usage;
406 BufferMap& buffers = clients_[request->client_id];
407 DCHECK(buffers.find(new_id) == buffers.end());
409 // Allocate shared memory buffer as fallback.
410 buffers[new_id] = BufferInfo(request->size, gfx::SHARED_MEMORY_BUFFER,
411 request->format, request->usage, 0);
412 // Note: Unretained is safe as IO thread is stopped before manager is
413 // destroyed.
414 request->result = GpuMemoryBufferImplSharedMemory::Create(
415 new_id, request->size, request->format,
416 base::Bind(
417 &GpuMemoryBufferDeleted,
418 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
419 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO,
420 base::Unretained(this), new_id, request->client_id)));
421 request->event.Signal();
424 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForSurfaceOnIO(
425 AllocateGpuMemoryBufferRequest* request,
426 const gfx::GpuMemoryBufferHandle& handle) {
427 DCHECK_CURRENTLY_ON(BrowserThread::IO);
429 // Early out if factory failed to allocate the buffer.
430 if (handle.is_null()) {
431 request->event.Signal();
432 return;
435 // Note: Unretained is safe as IO thread is stopped before manager is
436 // destroyed.
437 request->result = GpuMemoryBufferImpl::CreateFromHandle(
438 handle, request->size, request->format, request->usage,
439 base::Bind(
440 &GpuMemoryBufferDeleted,
441 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
442 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO,
443 base::Unretained(this), handle.id, request->client_id)));
444 request->event.Signal();
447 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
448 gfx::GpuMemoryBufferId id,
449 const gfx::Size& size,
450 gfx::GpuMemoryBuffer::Format format,
451 gfx::GpuMemoryBuffer::Usage usage,
452 int client_id,
453 int surface_id,
454 bool reused_gpu_process,
455 const AllocationCallback& callback) {
456 DCHECK_CURRENTLY_ON(BrowserThread::IO);
458 BufferMap& buffers = clients_[client_id];
459 DCHECK(buffers.find(id) == buffers.end());
461 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
462 if (!host) {
463 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
464 CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE);
465 if (!host) {
466 LOG(ERROR) << "Failed to launch GPU process.";
467 callback.Run(gfx::GpuMemoryBufferHandle());
468 return;
470 gpu_host_id_ = host->host_id();
471 reused_gpu_process = false;
472 } else {
473 if (reused_gpu_process) {
474 // We come here if we retried to allocate the buffer because of a
475 // failure in GpuMemoryBufferAllocatedOnIO, but we ended up with the
476 // same process ID, meaning the failure was not because of a channel
477 // error, but another reason. So fail now.
478 LOG(ERROR) << "Failed to allocate GpuMemoryBuffer.";
479 callback.Run(gfx::GpuMemoryBufferHandle());
480 return;
482 reused_gpu_process = true;
485 // Note: Handling of cases where the client is removed before the allocation
486 // completes is less subtle if we set the buffer type to EMPTY_BUFFER here
487 // and verify that this has not changed when allocation completes.
488 buffers[id] = BufferInfo(size, gfx::EMPTY_BUFFER, format, usage, 0);
490 // Note: Unretained is safe as IO thread is stopped before manager is
491 // destroyed.
492 host->CreateGpuMemoryBuffer(
493 id, size, format, usage, client_id, surface_id,
494 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO,
495 base::Unretained(this), id, client_id, surface_id,
496 gpu_host_id_, reused_gpu_process, callback));
499 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
500 gfx::GpuMemoryBufferId id,
501 int client_id,
502 int surface_id,
503 int gpu_host_id,
504 bool reused_gpu_process,
505 const AllocationCallback& callback,
506 const gfx::GpuMemoryBufferHandle& handle) {
507 DCHECK_CURRENTLY_ON(BrowserThread::IO);
509 ClientMap::iterator client_it = clients_.find(client_id);
511 // This can happen if client is removed while the buffer is being allocated.
512 if (client_it == clients_.end()) {
513 if (!handle.is_null()) {
514 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id);
515 if (host)
516 host->DestroyGpuMemoryBuffer(handle.id, client_id, 0);
518 callback.Run(gfx::GpuMemoryBufferHandle());
519 return;
522 BufferMap& buffers = client_it->second;
524 BufferMap::iterator buffer_it = buffers.find(id);
525 DCHECK(buffer_it != buffers.end());
526 DCHECK_EQ(buffer_it->second.type, gfx::EMPTY_BUFFER);
528 // If the handle isn't valid, that means that the GPU process crashed or is
529 // misbehaving.
530 bool valid_handle = !handle.is_null() && handle.id == id;
531 if (!valid_handle) {
532 // If we failed after re-using the GPU process, it may have died in the
533 // mean time. Retry to have a chance to create a fresh GPU process.
534 if (handle.is_null() && reused_gpu_process) {
535 DVLOG(1) << "Failed to create buffer through existing GPU process. "
536 "Trying to restart GPU process.";
537 // If the GPU process has already been restarted, retry without failure
538 // when GPU process host ID already exists.
539 if (gpu_host_id != gpu_host_id_)
540 reused_gpu_process = false;
541 gfx::Size size = buffer_it->second.size;
542 gfx::GpuMemoryBuffer::Format format = buffer_it->second.format;
543 gfx::GpuMemoryBuffer::Usage usage = buffer_it->second.usage;
544 // Remove the buffer entry and call AllocateGpuMemoryBufferOnIO again.
545 buffers.erase(buffer_it);
546 AllocateGpuMemoryBufferOnIO(id, size, format, usage, client_id,
547 surface_id, reused_gpu_process, callback);
548 } else {
549 // Remove the buffer entry and run the allocation callback with an empty
550 // handle to indicate failure.
551 buffers.erase(buffer_it);
552 callback.Run(gfx::GpuMemoryBufferHandle());
554 return;
557 // Store the type and host id of this buffer so it can be cleaned up if the
558 // client is removed.
559 buffer_it->second.type = handle.type;
560 buffer_it->second.gpu_host_id = gpu_host_id;
562 callback.Run(handle);
565 void BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO(
566 gfx::GpuMemoryBufferId id,
567 int client_id,
568 uint32 sync_point) {
569 DCHECK_CURRENTLY_ON(BrowserThread::IO);
570 DCHECK(clients_.find(client_id) != clients_.end());
572 BufferMap& buffers = clients_[client_id];
574 BufferMap::iterator buffer_it = buffers.find(id);
575 if (buffer_it == buffers.end()) {
576 LOG(ERROR) << "Invalid GpuMemoryBuffer ID for client.";
577 return;
580 // This can happen if a client managed to call this while a buffer is in the
581 // process of being allocated.
582 if (buffer_it->second.type == gfx::EMPTY_BUFFER) {
583 LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
584 return;
587 GpuProcessHost* host = GpuProcessHost::FromID(buffer_it->second.gpu_host_id);
588 if (host)
589 host->DestroyGpuMemoryBuffer(id, client_id, sync_point);
591 buffers.erase(buffer_it);
594 } // namespace content