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/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/generic_shared_memory_id_generator.h"
18 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
19 #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
20 #include "content/common/gpu/gpu_memory_buffer_factory_shared_memory.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/common/content_switches.h"
23 #include "gpu/GLES2/gl2extchromium.h"
24 #include "ui/gfx/buffer_format_util.h"
25 #include "ui/gl/gl_switches.h"
27 #if defined(OS_MACOSX)
28 #include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
31 #if defined(OS_ANDROID)
32 #include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
35 #if defined(USE_OZONE)
36 #include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_pixmap.h"
42 void GpuMemoryBufferDeleted(
43 scoped_refptr
<base::SingleThreadTaskRunner
> destruction_task_runner
,
44 const GpuMemoryBufferImpl::DestructionCallback
& destruction_callback
,
46 destruction_task_runner
->PostTask(
47 FROM_HERE
, base::Bind(destruction_callback
, sync_point
));
50 bool IsGpuMemoryBufferFactoryConfigurationSupported(
51 gfx::GpuMemoryBufferType type
,
52 const GpuMemoryBufferFactory::Configuration
& configuration
) {
54 case gfx::SHARED_MEMORY_BUFFER
:
55 return GpuMemoryBufferFactorySharedMemory::
56 IsGpuMemoryBufferConfigurationSupported(configuration
.format
,
58 #if defined(OS_MACOSX)
59 case gfx::IO_SURFACE_BUFFER
:
60 return GpuMemoryBufferFactoryIOSurface::
61 IsGpuMemoryBufferConfigurationSupported(configuration
.format
,
64 #if defined(OS_ANDROID)
65 case gfx::SURFACE_TEXTURE_BUFFER
:
66 return GpuMemoryBufferFactorySurfaceTexture::
67 IsGpuMemoryBufferConfigurationSupported(configuration
.format
,
70 #if defined(USE_OZONE)
71 case gfx::OZONE_NATIVE_PIXMAP
:
72 return GpuMemoryBufferFactoryOzoneNativePixmap::
73 IsGpuMemoryBufferConfigurationSupported(configuration
.format
,
82 gfx::GpuMemoryBufferType
GetGpuMemoryBufferFactoryType() {
83 std::vector
<gfx::GpuMemoryBufferType
> supported_types
;
84 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types
);
85 DCHECK(!supported_types
.empty());
87 // The GPU service will always use the preferred type.
88 return supported_types
[0];
91 std::vector
<GpuMemoryBufferFactory::Configuration
>
92 GetSupportedGpuMemoryBufferConfigurations(gfx::GpuMemoryBufferType type
) {
93 std::vector
<GpuMemoryBufferFactory::Configuration
> configurations
;
94 #if defined(OS_MACOSX)
95 bool enable_native_gpu_memory_buffers
=
96 !base::CommandLine::ForCurrentProcess()->HasSwitch(
97 switches::kDisableNativeGpuMemoryBuffers
);
99 bool enable_native_gpu_memory_buffers
=
100 base::CommandLine::ForCurrentProcess()->HasSwitch(
101 switches::kEnableNativeGpuMemoryBuffers
);
104 // Disable native buffers when using Mesa.
105 if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
106 switches::kUseGL
) == gfx::kGLImplementationOSMesaName
) {
107 enable_native_gpu_memory_buffers
= false;
110 if (enable_native_gpu_memory_buffers
) {
111 const GpuMemoryBufferFactory::Configuration kNativeConfigurations
[] = {
112 {gfx::BufferFormat::R_8
, gfx::BufferUsage::MAP
},
113 {gfx::BufferFormat::R_8
, gfx::BufferUsage::PERSISTENT_MAP
},
114 {gfx::BufferFormat::RGBA_4444
, gfx::BufferUsage::MAP
},
115 {gfx::BufferFormat::RGBA_4444
, gfx::BufferUsage::PERSISTENT_MAP
},
116 {gfx::BufferFormat::RGBA_8888
, gfx::BufferUsage::MAP
},
117 {gfx::BufferFormat::RGBA_8888
, gfx::BufferUsage::PERSISTENT_MAP
},
118 {gfx::BufferFormat::BGRA_8888
, gfx::BufferUsage::MAP
},
119 {gfx::BufferFormat::BGRA_8888
, gfx::BufferUsage::PERSISTENT_MAP
},
120 {gfx::BufferFormat::UYVY_422
, gfx::BufferUsage::MAP
},
121 {gfx::BufferFormat::UYVY_422
, gfx::BufferUsage::PERSISTENT_MAP
},
122 {gfx::BufferFormat::YUV_420_BIPLANAR
, gfx::BufferUsage::MAP
},
123 {gfx::BufferFormat::YUV_420_BIPLANAR
, gfx::BufferUsage::PERSISTENT_MAP
},
125 for (auto& configuration
: kNativeConfigurations
) {
126 if (IsGpuMemoryBufferFactoryConfigurationSupported(type
, configuration
))
127 configurations
.push_back(configuration
);
131 #if defined(USE_OZONE) || defined(OS_MACOSX)
132 const GpuMemoryBufferFactory::Configuration kScanoutConfigurations
[] = {
133 {gfx::BufferFormat::BGRA_8888
, gfx::BufferUsage::SCANOUT
},
134 {gfx::BufferFormat::BGRX_8888
, gfx::BufferUsage::SCANOUT
},
135 {gfx::BufferFormat::UYVY_422
, gfx::BufferUsage::SCANOUT
},
136 {gfx::BufferFormat::YUV_420_BIPLANAR
, gfx::BufferUsage::SCANOUT
},
138 for (auto& configuration
: kScanoutConfigurations
) {
139 if (IsGpuMemoryBufferFactoryConfigurationSupported(type
, configuration
))
140 configurations
.push_back(configuration
);
144 return configurations
;
147 BrowserGpuMemoryBufferManager
* g_gpu_memory_buffer_manager
= nullptr;
151 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest
{
152 AllocateGpuMemoryBufferRequest(const gfx::Size
& size
,
153 gfx::BufferFormat format
,
154 gfx::BufferUsage usage
,
157 : event(true, false),
161 client_id(client_id
),
162 surface_id(surface_id
) {}
163 ~AllocateGpuMemoryBufferRequest() {}
164 base::WaitableEvent event
;
166 gfx::BufferFormat format
;
167 gfx::BufferUsage usage
;
170 scoped_ptr
<gfx::GpuMemoryBuffer
> result
;
173 BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(
175 uint64_t gpu_client_tracing_id
)
176 : factory_type_(GetGpuMemoryBufferFactoryType()),
177 supported_configurations_(
178 GetSupportedGpuMemoryBufferConfigurations(factory_type_
)),
179 gpu_client_id_(gpu_client_id
),
180 gpu_client_tracing_id_(gpu_client_tracing_id
),
182 DCHECK(!g_gpu_memory_buffer_manager
);
183 g_gpu_memory_buffer_manager
= this;
186 BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() {
187 g_gpu_memory_buffer_manager
= nullptr;
191 BrowserGpuMemoryBufferManager
* BrowserGpuMemoryBufferManager::current() {
192 return g_gpu_memory_buffer_manager
;
196 uint32
BrowserGpuMemoryBufferManager::GetImageTextureTarget(
197 gfx::BufferFormat format
,
198 gfx::BufferUsage usage
) {
199 gfx::GpuMemoryBufferType type
= GetGpuMemoryBufferFactoryType();
200 for (auto& configuration
: GetSupportedGpuMemoryBufferConfigurations(type
)) {
201 if (configuration
.format
!= format
|| configuration
.usage
!= usage
)
205 case gfx::SURFACE_TEXTURE_BUFFER
:
206 case gfx::OZONE_NATIVE_PIXMAP
:
207 // GPU memory buffers that are shared with the GL using EGLImages
208 // require TEXTURE_EXTERNAL_OES.
209 return GL_TEXTURE_EXTERNAL_OES
;
210 case gfx::IO_SURFACE_BUFFER
:
211 // IOSurface backed images require GL_TEXTURE_RECTANGLE_ARB.
212 return GL_TEXTURE_RECTANGLE_ARB
;
214 return GL_TEXTURE_2D
;
218 return GL_TEXTURE_2D
;
221 scoped_ptr
<gfx::GpuMemoryBuffer
>
222 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(const gfx::Size
& size
,
223 gfx::BufferFormat format
,
224 gfx::BufferUsage usage
) {
225 return AllocateGpuMemoryBufferForSurface(size
, format
, usage
, 0);
228 scoped_ptr
<gfx::GpuMemoryBuffer
>
229 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout(
230 const gfx::Size
& size
,
231 gfx::BufferFormat format
,
233 DCHECK_GT(surface_id
, 0);
234 return AllocateGpuMemoryBufferForSurface(
235 size
, format
, gfx::BufferUsage::SCANOUT
, surface_id
);
238 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
239 gfx::GpuMemoryBufferId id
,
240 const gfx::Size
& size
,
241 gfx::BufferFormat format
,
242 gfx::BufferUsage usage
,
243 base::ProcessHandle child_process_handle
,
245 const AllocationCallback
& callback
) {
246 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
248 // Use service side allocation if this is a supported configuration.
249 if (IsGpuMemoryBufferConfigurationSupported(format
, usage
)) {
250 AllocateGpuMemoryBufferOnIO(id
, size
, format
, usage
, child_client_id
, 0,
255 // Early out if we cannot fallback to shared memory buffer.
256 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format
) ||
257 !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage
) ||
258 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size
, format
)) {
259 callback
.Run(gfx::GpuMemoryBufferHandle());
263 BufferMap
& buffers
= clients_
[child_client_id
];
265 // Allocate shared memory buffer as fallback.
266 auto insert_result
= buffers
.insert(std::make_pair(
267 id
, BufferInfo(size
, gfx::SHARED_MEMORY_BUFFER
, format
, usage
, 0)));
268 if (!insert_result
.second
) {
269 DLOG(ERROR
) << "Child process attempted to allocate a GpuMemoryBuffer with "
271 callback
.Run(gfx::GpuMemoryBufferHandle());
275 callback
.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
276 id
, size
, format
, child_process_handle
));
279 gfx::GpuMemoryBuffer
*
280 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
281 ClientBuffer buffer
) {
282 return GpuMemoryBufferImpl::FromClientBuffer(buffer
);
285 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint(
286 gfx::GpuMemoryBuffer
* buffer
,
288 static_cast<GpuMemoryBufferImpl
*>(buffer
)
289 ->set_destruction_sync_point(sync_point
);
292 bool BrowserGpuMemoryBufferManager::OnMemoryDump(
293 const base::trace_event::MemoryDumpArgs
& args
,
294 base::trace_event::ProcessMemoryDump
* pmd
) {
295 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
297 for (const auto& client
: clients_
) {
298 int client_id
= client
.first
;
300 for (const auto& buffer
: client
.second
) {
301 if (buffer
.second
.type
== gfx::EMPTY_BUFFER
)
304 gfx::GpuMemoryBufferId buffer_id
= buffer
.first
;
305 base::trace_event::MemoryAllocatorDump
* dump
=
306 pmd
->CreateAllocatorDump(base::StringPrintf(
307 "gpumemorybuffer/client_%d/buffer_%d", client_id
, buffer_id
.id
));
311 size_t buffer_size_in_bytes
= gfx::BufferSizeForBufferFormat(
312 buffer
.second
.size
, buffer
.second
.format
);
313 dump
->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize
,
314 base::trace_event::MemoryAllocatorDump::kUnitsBytes
,
315 buffer_size_in_bytes
);
317 // Create the cross-process ownership edge. If the client creates a
318 // corresponding dump for the same buffer, this will avoid to
319 // double-count them in tracing. If, instead, no other process will emit a
320 // dump with the same guid, the segment will be accounted to the browser.
321 uint64 client_tracing_process_id
= ClientIdToTracingProcessId(client_id
);
323 base::trace_event::MemoryAllocatorDumpGuid shared_buffer_guid
=
324 gfx::GetGpuMemoryBufferGUIDForTracing(client_tracing_process_id
,
326 pmd
->CreateSharedGlobalAllocatorDump(shared_buffer_guid
);
327 pmd
->AddOwnershipEdge(dump
->guid(), shared_buffer_guid
);
334 void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
335 gfx::GpuMemoryBufferId id
,
336 base::ProcessHandle child_process_handle
,
339 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
341 DestroyGpuMemoryBufferOnIO(id
, child_client_id
, sync_point
);
344 void BrowserGpuMemoryBufferManager::ProcessRemoved(
345 base::ProcessHandle process_handle
,
347 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
349 ClientMap::iterator client_it
= clients_
.find(client_id
);
350 if (client_it
== clients_
.end())
353 for (const auto& buffer
: client_it
->second
) {
354 // This might happen if buffer is currenlty in the process of being
355 // allocated. The buffer will in that case be cleaned up when allocation
357 if (buffer
.second
.type
== gfx::EMPTY_BUFFER
)
360 GpuProcessHost
* host
= GpuProcessHost::FromID(buffer
.second
.gpu_host_id
);
362 host
->DestroyGpuMemoryBuffer(buffer
.first
, client_id
, 0);
365 clients_
.erase(client_it
);
368 scoped_ptr
<gfx::GpuMemoryBuffer
>
369 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface(
370 const gfx::Size
& size
,
371 gfx::BufferFormat format
,
372 gfx::BufferUsage usage
,
374 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO
));
376 AllocateGpuMemoryBufferRequest
request(size
, format
, usage
, gpu_client_id_
,
378 BrowserThread::PostTask(
379 BrowserThread::IO
, FROM_HERE
,
381 &BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO
,
382 base::Unretained(this), // Safe as we wait for result below.
383 base::Unretained(&request
)));
385 // We're blocking the UI thread, which is generally undesirable.
388 "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface");
389 base::ThreadRestrictions::ScopedAllowWait allow_wait
;
390 request
.event
.Wait();
391 return request
.result
.Pass();
394 bool BrowserGpuMemoryBufferManager::IsGpuMemoryBufferConfigurationSupported(
395 gfx::BufferFormat format
,
396 gfx::BufferUsage usage
) const {
397 for (auto& configuration
: supported_configurations_
) {
398 if (configuration
.format
== format
&& configuration
.usage
== usage
)
404 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO(
405 AllocateGpuMemoryBufferRequest
* request
) {
406 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
408 gfx::GpuMemoryBufferId new_id
= content::GetNextGenericSharedMemoryId();
410 // Use service side allocation if this is a supported configuration.
411 if (IsGpuMemoryBufferConfigurationSupported(request
->format
,
413 // Note: Unretained is safe as this is only used for synchronous allocation
414 // from a non-IO thread.
415 AllocateGpuMemoryBufferOnIO(
416 new_id
, request
->size
, request
->format
, request
->usage
,
417 request
->client_id
, request
->surface_id
, false,
418 base::Bind(&BrowserGpuMemoryBufferManager::
419 GpuMemoryBufferAllocatedForSurfaceOnIO
,
420 base::Unretained(this), base::Unretained(request
)));
424 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(request
->format
))
425 << static_cast<int>(request
->format
);
426 DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request
->usage
))
427 << static_cast<int>(request
->usage
);
429 BufferMap
& buffers
= clients_
[request
->client_id
];
431 // Allocate shared memory buffer as fallback.
432 auto insert_result
= buffers
.insert(std::make_pair(
433 new_id
, BufferInfo(request
->size
, gfx::SHARED_MEMORY_BUFFER
,
434 request
->format
, request
->usage
, 0)));
435 DCHECK(insert_result
.second
);
437 // Note: Unretained is safe as IO thread is stopped before manager is
439 request
->result
= GpuMemoryBufferImplSharedMemory::Create(
440 new_id
, request
->size
, request
->format
,
442 &GpuMemoryBufferDeleted
,
443 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
),
444 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO
,
445 base::Unretained(this), new_id
, request
->client_id
)));
446 request
->event
.Signal();
449 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForSurfaceOnIO(
450 AllocateGpuMemoryBufferRequest
* request
,
451 const gfx::GpuMemoryBufferHandle
& handle
) {
452 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
454 // Early out if factory failed to allocate the buffer.
455 if (handle
.is_null()) {
456 request
->event
.Signal();
460 // Note: Unretained is safe as IO thread is stopped before manager is
462 request
->result
= GpuMemoryBufferImpl::CreateFromHandle(
463 handle
, request
->size
, request
->format
, request
->usage
,
465 &GpuMemoryBufferDeleted
,
466 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
),
467 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO
,
468 base::Unretained(this), handle
.id
, request
->client_id
)));
469 request
->event
.Signal();
472 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
473 gfx::GpuMemoryBufferId id
,
474 const gfx::Size
& size
,
475 gfx::BufferFormat format
,
476 gfx::BufferUsage usage
,
479 bool reused_gpu_process
,
480 const AllocationCallback
& callback
) {
481 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
483 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id_
);
485 host
= GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED
,
486 CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE
);
488 LOG(ERROR
) << "Failed to launch GPU process.";
489 callback
.Run(gfx::GpuMemoryBufferHandle());
492 gpu_host_id_
= host
->host_id();
493 reused_gpu_process
= false;
495 if (reused_gpu_process
) {
496 // We come here if we retried to allocate the buffer because of a
497 // failure in GpuMemoryBufferAllocatedOnIO, but we ended up with the
498 // same process ID, meaning the failure was not because of a channel
499 // error, but another reason. So fail now.
500 LOG(ERROR
) << "Failed to allocate GpuMemoryBuffer.";
501 callback
.Run(gfx::GpuMemoryBufferHandle());
504 reused_gpu_process
= true;
507 BufferMap
& buffers
= clients_
[client_id
];
509 // Note: Handling of cases where the client is removed before the allocation
510 // completes is less subtle if we set the buffer type to EMPTY_BUFFER here
511 // and verify that this has not changed when allocation completes.
512 auto insert_result
= buffers
.insert(std::make_pair(
513 id
, BufferInfo(size
, gfx::EMPTY_BUFFER
, format
, usage
, 0)));
514 if (!insert_result
.second
) {
515 DLOG(ERROR
) << "Child process attempted to allocate a GpuMemoryBuffer with "
517 callback
.Run(gfx::GpuMemoryBufferHandle());
521 // Note: Unretained is safe as IO thread is stopped before manager is
523 host
->CreateGpuMemoryBuffer(
524 id
, size
, format
, usage
, client_id
, surface_id
,
525 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO
,
526 base::Unretained(this), id
, client_id
, surface_id
,
527 gpu_host_id_
, reused_gpu_process
, callback
));
530 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
531 gfx::GpuMemoryBufferId id
,
535 bool reused_gpu_process
,
536 const AllocationCallback
& callback
,
537 const gfx::GpuMemoryBufferHandle
& handle
) {
538 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
540 ClientMap::iterator client_it
= clients_
.find(client_id
);
542 // This can happen if client is removed while the buffer is being allocated.
543 if (client_it
== clients_
.end()) {
544 if (!handle
.is_null()) {
545 GpuProcessHost
* host
= GpuProcessHost::FromID(gpu_host_id
);
547 host
->DestroyGpuMemoryBuffer(handle
.id
, client_id
, 0);
549 callback
.Run(gfx::GpuMemoryBufferHandle());
553 BufferMap
& buffers
= client_it
->second
;
555 BufferMap::iterator buffer_it
= buffers
.find(id
);
556 DCHECK(buffer_it
!= buffers
.end());
557 DCHECK_EQ(buffer_it
->second
.type
, gfx::EMPTY_BUFFER
);
559 // If the handle isn't valid, that means that the GPU process crashed or is
561 bool valid_handle
= !handle
.is_null() && handle
.id
== id
;
563 // If we failed after re-using the GPU process, it may have died in the
564 // mean time. Retry to have a chance to create a fresh GPU process.
565 if (handle
.is_null() && reused_gpu_process
) {
566 DVLOG(1) << "Failed to create buffer through existing GPU process. "
567 "Trying to restart GPU process.";
568 // If the GPU process has already been restarted, retry without failure
569 // when GPU process host ID already exists.
570 if (gpu_host_id
!= gpu_host_id_
)
571 reused_gpu_process
= false;
572 gfx::Size size
= buffer_it
->second
.size
;
573 gfx::BufferFormat format
= buffer_it
->second
.format
;
574 gfx::BufferUsage usage
= buffer_it
->second
.usage
;
575 // Remove the buffer entry and call AllocateGpuMemoryBufferOnIO again.
576 buffers
.erase(buffer_it
);
577 AllocateGpuMemoryBufferOnIO(id
, size
, format
, usage
, client_id
,
578 surface_id
, reused_gpu_process
, callback
);
580 // Remove the buffer entry and run the allocation callback with an empty
581 // handle to indicate failure.
582 buffers
.erase(buffer_it
);
583 callback
.Run(gfx::GpuMemoryBufferHandle());
588 // Store the type and host id of this buffer so it can be cleaned up if the
589 // client is removed.
590 buffer_it
->second
.type
= handle
.type
;
591 buffer_it
->second
.gpu_host_id
= gpu_host_id
;
593 callback
.Run(handle
);
596 void BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO(
597 gfx::GpuMemoryBufferId id
,
600 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
601 DCHECK(clients_
.find(client_id
) != clients_
.end());
603 BufferMap
& buffers
= clients_
[client_id
];
605 BufferMap::iterator buffer_it
= buffers
.find(id
);
606 if (buffer_it
== buffers
.end()) {
607 LOG(ERROR
) << "Invalid GpuMemoryBuffer ID for client.";
611 // This can happen if a client managed to call this while a buffer is in the
612 // process of being allocated.
613 if (buffer_it
->second
.type
== gfx::EMPTY_BUFFER
) {
614 LOG(ERROR
) << "Invalid GpuMemoryBuffer type.";
618 GpuProcessHost
* host
= GpuProcessHost::FromID(buffer_it
->second
.gpu_host_id
);
620 host
->DestroyGpuMemoryBuffer(id
, client_id
, sync_point
);
622 buffers
.erase(buffer_it
);
625 uint64_t BrowserGpuMemoryBufferManager::ClientIdToTracingProcessId(
626 int client_id
) const {
627 if (client_id
== gpu_client_id_
) {
628 // The gpu_client uses a fixed tracing ID.
629 return gpu_client_tracing_id_
;
632 // In normal cases, |client_id| is a child process id, so we can perform
633 // the standard conversion.
634 return ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
638 } // namespace content