OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" | 5 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" |
6 | 6 |
7 #include "base/atomic_sequence_num.h" | 7 #include "base/atomic_sequence_num.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
11 #include "base/synchronization/waitable_event.h" | 11 #include "base/synchronization/waitable_event.h" |
12 #include "base/threading/thread_restrictions.h" | 12 #include "base/threading/thread_restrictions.h" |
13 #include "base/trace_event/process_memory_dump.h" | 13 #include "base/trace_event/process_memory_dump.h" |
14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
15 #include "content/browser/gpu/gpu_process_host.h" | 15 #include "content/browser/gpu/gpu_process_host.h" |
16 #include "content/common/child_process_host_impl.h" | 16 #include "content/common/child_process_host_impl.h" |
| 17 #include "content/common/generic_shared_memory_id_generator.h" |
17 #include "content/common/gpu/client/gpu_memory_buffer_impl.h" | 18 #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/client/gpu_memory_buffer_impl_shared_memory.h" |
19 #include "content/common/gpu/gpu_memory_buffer_factory_shared_memory.h" | 20 #include "content/common/gpu/gpu_memory_buffer_factory_shared_memory.h" |
20 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
21 #include "content/public/common/content_switches.h" | 22 #include "content/public/common/content_switches.h" |
22 #include "gpu/GLES2/gl2extchromium.h" | 23 #include "gpu/GLES2/gl2extchromium.h" |
23 #include "ui/gl/gl_switches.h" | 24 #include "ui/gl/gl_switches.h" |
24 | 25 |
25 #if defined(OS_MACOSX) | 26 #if defined(OS_MACOSX) |
26 #include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h" | 27 #include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h" |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration)) | 135 if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration)) |
135 configurations.push_back(configuration); | 136 configurations.push_back(configuration); |
136 } | 137 } |
137 #endif | 138 #endif |
138 | 139 |
139 return configurations; | 140 return configurations; |
140 } | 141 } |
141 | 142 |
142 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr; | 143 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr; |
143 | 144 |
144 // Global atomic to generate gpu memory buffer unique IDs. | |
145 base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id; | |
146 | |
147 } // namespace | 145 } // namespace |
148 | 146 |
149 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest { | 147 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest { |
150 AllocateGpuMemoryBufferRequest(const gfx::Size& size, | 148 AllocateGpuMemoryBufferRequest(const gfx::Size& size, |
151 gfx::BufferFormat format, | 149 gfx::BufferFormat format, |
152 gfx::BufferUsage usage, | 150 gfx::BufferUsage usage, |
153 int client_id, | 151 int client_id, |
154 int surface_id) | 152 int surface_id) |
155 : event(true, false), | 153 : event(true, false), |
156 size(size), | 154 size(size), |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout( | 225 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout( |
228 const gfx::Size& size, | 226 const gfx::Size& size, |
229 gfx::BufferFormat format, | 227 gfx::BufferFormat format, |
230 int32 surface_id) { | 228 int32 surface_id) { |
231 DCHECK_GT(surface_id, 0); | 229 DCHECK_GT(surface_id, 0); |
232 return AllocateGpuMemoryBufferForSurface( | 230 return AllocateGpuMemoryBufferForSurface( |
233 size, format, gfx::BufferUsage::SCANOUT, surface_id); | 231 size, format, gfx::BufferUsage::SCANOUT, surface_id); |
234 } | 232 } |
235 | 233 |
236 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess( | 234 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess( |
| 235 gfx::GpuMemoryBufferId id, |
237 const gfx::Size& size, | 236 const gfx::Size& size, |
238 gfx::BufferFormat format, | 237 gfx::BufferFormat format, |
239 gfx::BufferUsage usage, | 238 gfx::BufferUsage usage, |
240 base::ProcessHandle child_process_handle, | 239 base::ProcessHandle child_process_handle, |
241 int child_client_id, | 240 int child_client_id, |
242 const AllocationCallback& callback) { | 241 const AllocationCallback& callback) { |
243 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 242 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
244 | 243 |
245 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext(); | |
246 | |
247 // Use service side allocation if this is a supported configuration. | 244 // Use service side allocation if this is a supported configuration. |
248 if (IsGpuMemoryBufferConfigurationSupported(format, usage)) { | 245 if (IsGpuMemoryBufferConfigurationSupported(format, usage)) { |
249 AllocateGpuMemoryBufferOnIO(new_id, size, format, usage, child_client_id, 0, | 246 AllocateGpuMemoryBufferOnIO(id, size, format, usage, child_client_id, 0, |
250 false, callback); | 247 false, callback); |
251 return; | 248 return; |
252 } | 249 } |
253 | 250 |
254 // Early out if we cannot fallback to shared memory buffer. | 251 // Early out if we cannot fallback to shared memory buffer. |
255 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) || | 252 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) || |
256 !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) || | 253 !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) || |
257 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) { | 254 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) { |
258 callback.Run(gfx::GpuMemoryBufferHandle()); | 255 callback.Run(gfx::GpuMemoryBufferHandle()); |
259 return; | 256 return; |
260 } | 257 } |
261 | 258 |
262 BufferMap& buffers = clients_[child_client_id]; | 259 BufferMap& buffers = clients_[child_client_id]; |
263 DCHECK(buffers.find(new_id) == buffers.end()); | |
264 | 260 |
265 // Allocate shared memory buffer as fallback. | 261 // Allocate shared memory buffer as fallback. |
266 buffers[new_id] = | 262 auto insert_result = buffers.insert(std::make_pair( |
267 BufferInfo(size, gfx::SHARED_MEMORY_BUFFER, format, usage, 0); | 263 id, BufferInfo(size, gfx::SHARED_MEMORY_BUFFER, format, usage, 0))); |
| 264 if (!insert_result.second) { |
| 265 DLOG(ERROR) << "Child process attempted to allocate a GpuMemoryBuffer with " |
| 266 "an existing ID."; |
| 267 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 268 return; |
| 269 } |
| 270 |
268 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( | 271 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( |
269 new_id, size, format, child_process_handle)); | 272 id, size, format, child_process_handle)); |
270 } | 273 } |
271 | 274 |
272 gfx::GpuMemoryBuffer* | 275 gfx::GpuMemoryBuffer* |
273 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer( | 276 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer( |
274 ClientBuffer buffer) { | 277 ClientBuffer buffer) { |
275 return GpuMemoryBufferImpl::FromClientBuffer(buffer); | 278 return GpuMemoryBufferImpl::FromClientBuffer(buffer); |
276 } | 279 } |
277 | 280 |
278 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint( | 281 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint( |
279 gfx::GpuMemoryBuffer* buffer, | 282 gfx::GpuMemoryBuffer* buffer, |
(...skipping 10 matching lines...) Expand all Loading... |
290 for (const auto& client : clients_) { | 293 for (const auto& client : clients_) { |
291 int client_id = client.first; | 294 int client_id = client.first; |
292 | 295 |
293 for (const auto& buffer : client.second) { | 296 for (const auto& buffer : client.second) { |
294 if (buffer.second.type == gfx::EMPTY_BUFFER) | 297 if (buffer.second.type == gfx::EMPTY_BUFFER) |
295 continue; | 298 continue; |
296 | 299 |
297 gfx::GpuMemoryBufferId buffer_id = buffer.first; | 300 gfx::GpuMemoryBufferId buffer_id = buffer.first; |
298 base::trace_event::MemoryAllocatorDump* dump = | 301 base::trace_event::MemoryAllocatorDump* dump = |
299 pmd->CreateAllocatorDump(base::StringPrintf( | 302 pmd->CreateAllocatorDump(base::StringPrintf( |
300 "gpumemorybuffer/client_%d/buffer_%d", client_id, buffer_id)); | 303 "gpumemorybuffer/client_%d/buffer_%d", client_id, buffer_id.id)); |
301 if (!dump) | 304 if (!dump) |
302 return false; | 305 return false; |
303 | 306 |
304 size_t buffer_size_in_bytes = 0; | 307 size_t buffer_size_in_bytes = 0; |
305 // Note: BufferSizeInBytes returns an approximated size for the buffer | 308 // Note: BufferSizeInBytes returns an approximated size for the buffer |
306 // but the factory can be made to return the exact size if this | 309 // but the factory can be made to return the exact size if this |
307 // approximation is not good enough. | 310 // approximation is not good enough. |
308 bool valid_size = GpuMemoryBufferImpl::BufferSizeInBytes( | 311 bool valid_size = GpuMemoryBufferImpl::BufferSizeInBytes( |
309 buffer.second.size, buffer.second.format, &buffer_size_in_bytes); | 312 buffer.second.size, buffer.second.format, &buffer_size_in_bytes); |
310 DCHECK(valid_size); | 313 DCHECK(valid_size); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 if (configuration.format == format && configuration.usage == usage) | 400 if (configuration.format == format && configuration.usage == usage) |
398 return true; | 401 return true; |
399 } | 402 } |
400 return false; | 403 return false; |
401 } | 404 } |
402 | 405 |
403 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO( | 406 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO( |
404 AllocateGpuMemoryBufferRequest* request) { | 407 AllocateGpuMemoryBufferRequest* request) { |
405 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 408 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
406 | 409 |
407 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext(); | 410 gfx::GpuMemoryBufferId new_id = content::GetNextGenericSharedMemoryId(); |
408 | 411 |
409 // Use service side allocation if this is a supported configuration. | 412 // Use service side allocation if this is a supported configuration. |
410 if (IsGpuMemoryBufferConfigurationSupported(request->format, | 413 if (IsGpuMemoryBufferConfigurationSupported(request->format, |
411 request->usage)) { | 414 request->usage)) { |
412 // Note: Unretained is safe as this is only used for synchronous allocation | 415 // Note: Unretained is safe as this is only used for synchronous allocation |
413 // from a non-IO thread. | 416 // from a non-IO thread. |
414 AllocateGpuMemoryBufferOnIO( | 417 AllocateGpuMemoryBufferOnIO( |
415 new_id, request->size, request->format, request->usage, | 418 new_id, request->size, request->format, request->usage, |
416 request->client_id, request->surface_id, false, | 419 request->client_id, request->surface_id, false, |
417 base::Bind(&BrowserGpuMemoryBufferManager:: | 420 base::Bind(&BrowserGpuMemoryBufferManager:: |
418 GpuMemoryBufferAllocatedForSurfaceOnIO, | 421 GpuMemoryBufferAllocatedForSurfaceOnIO, |
419 base::Unretained(this), base::Unretained(request))); | 422 base::Unretained(this), base::Unretained(request))); |
420 return; | 423 return; |
421 } | 424 } |
422 | 425 |
423 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(request->format)) | 426 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(request->format)) |
424 << static_cast<int>(request->format); | 427 << static_cast<int>(request->format); |
425 DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage)) | 428 DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage)) |
426 << static_cast<int>(request->usage); | 429 << static_cast<int>(request->usage); |
427 | 430 |
428 BufferMap& buffers = clients_[request->client_id]; | 431 BufferMap& buffers = clients_[request->client_id]; |
429 DCHECK(buffers.find(new_id) == buffers.end()); | |
430 | 432 |
431 // Allocate shared memory buffer as fallback. | 433 // Allocate shared memory buffer as fallback. |
432 buffers[new_id] = BufferInfo(request->size, gfx::SHARED_MEMORY_BUFFER, | 434 auto insert_result = buffers.insert(std::make_pair( |
433 request->format, request->usage, 0); | 435 new_id, BufferInfo(request->size, gfx::SHARED_MEMORY_BUFFER, |
| 436 request->format, request->usage, 0))); |
| 437 DCHECK(insert_result.second); |
| 438 |
434 // Note: Unretained is safe as IO thread is stopped before manager is | 439 // Note: Unretained is safe as IO thread is stopped before manager is |
435 // destroyed. | 440 // destroyed. |
436 request->result = GpuMemoryBufferImplSharedMemory::Create( | 441 request->result = GpuMemoryBufferImplSharedMemory::Create( |
437 new_id, request->size, request->format, | 442 new_id, request->size, request->format, |
438 base::Bind( | 443 base::Bind( |
439 &GpuMemoryBufferDeleted, | 444 &GpuMemoryBufferDeleted, |
440 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), | 445 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), |
441 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO, | 446 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO, |
442 base::Unretained(this), new_id, request->client_id))); | 447 base::Unretained(this), new_id, request->client_id))); |
443 request->event.Signal(); | 448 request->event.Signal(); |
(...skipping 26 matching lines...) Expand all Loading... |
470 gfx::GpuMemoryBufferId id, | 475 gfx::GpuMemoryBufferId id, |
471 const gfx::Size& size, | 476 const gfx::Size& size, |
472 gfx::BufferFormat format, | 477 gfx::BufferFormat format, |
473 gfx::BufferUsage usage, | 478 gfx::BufferUsage usage, |
474 int client_id, | 479 int client_id, |
475 int surface_id, | 480 int surface_id, |
476 bool reused_gpu_process, | 481 bool reused_gpu_process, |
477 const AllocationCallback& callback) { | 482 const AllocationCallback& callback) { |
478 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 483 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
479 | 484 |
480 BufferMap& buffers = clients_[client_id]; | |
481 DCHECK(buffers.find(id) == buffers.end()); | |
482 | |
483 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); | 485 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); |
484 if (!host) { | 486 if (!host) { |
485 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, | 487 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, |
486 CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE); | 488 CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE); |
487 if (!host) { | 489 if (!host) { |
488 LOG(ERROR) << "Failed to launch GPU process."; | 490 LOG(ERROR) << "Failed to launch GPU process."; |
489 callback.Run(gfx::GpuMemoryBufferHandle()); | 491 callback.Run(gfx::GpuMemoryBufferHandle()); |
490 return; | 492 return; |
491 } | 493 } |
492 gpu_host_id_ = host->host_id(); | 494 gpu_host_id_ = host->host_id(); |
493 reused_gpu_process = false; | 495 reused_gpu_process = false; |
494 } else { | 496 } else { |
495 if (reused_gpu_process) { | 497 if (reused_gpu_process) { |
496 // We come here if we retried to allocate the buffer because of a | 498 // We come here if we retried to allocate the buffer because of a |
497 // failure in GpuMemoryBufferAllocatedOnIO, but we ended up with the | 499 // failure in GpuMemoryBufferAllocatedOnIO, but we ended up with the |
498 // same process ID, meaning the failure was not because of a channel | 500 // same process ID, meaning the failure was not because of a channel |
499 // error, but another reason. So fail now. | 501 // error, but another reason. So fail now. |
500 LOG(ERROR) << "Failed to allocate GpuMemoryBuffer."; | 502 LOG(ERROR) << "Failed to allocate GpuMemoryBuffer."; |
501 callback.Run(gfx::GpuMemoryBufferHandle()); | 503 callback.Run(gfx::GpuMemoryBufferHandle()); |
502 return; | 504 return; |
503 } | 505 } |
504 reused_gpu_process = true; | 506 reused_gpu_process = true; |
505 } | 507 } |
506 | 508 |
| 509 BufferMap& buffers = clients_[client_id]; |
| 510 |
507 // Note: Handling of cases where the client is removed before the allocation | 511 // Note: Handling of cases where the client is removed before the allocation |
508 // completes is less subtle if we set the buffer type to EMPTY_BUFFER here | 512 // completes is less subtle if we set the buffer type to EMPTY_BUFFER here |
509 // and verify that this has not changed when allocation completes. | 513 // and verify that this has not changed when allocation completes. |
510 buffers[id] = BufferInfo(size, gfx::EMPTY_BUFFER, format, usage, 0); | 514 auto insert_result = buffers.insert(std::make_pair( |
| 515 id, BufferInfo(size, gfx::EMPTY_BUFFER, format, usage, 0))); |
| 516 if (!insert_result.second) { |
| 517 DLOG(ERROR) << "Child process attempted to allocate a GpuMemoryBuffer with " |
| 518 "an existing ID."; |
| 519 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 520 return; |
| 521 } |
511 | 522 |
512 // Note: Unretained is safe as IO thread is stopped before manager is | 523 // Note: Unretained is safe as IO thread is stopped before manager is |
513 // destroyed. | 524 // destroyed. |
514 host->CreateGpuMemoryBuffer( | 525 host->CreateGpuMemoryBuffer( |
515 id, size, format, usage, client_id, surface_id, | 526 id, size, format, usage, client_id, surface_id, |
516 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO, | 527 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO, |
517 base::Unretained(this), id, client_id, surface_id, | 528 base::Unretained(this), id, client_id, surface_id, |
518 gpu_host_id_, reused_gpu_process, callback)); | 529 gpu_host_id_, reused_gpu_process, callback)); |
519 } | 530 } |
520 | 531 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 return gpu_client_tracing_id_; | 631 return gpu_client_tracing_id_; |
621 } | 632 } |
622 | 633 |
623 // In normal cases, |client_id| is a child process id, so we can perform | 634 // In normal cases, |client_id| is a child process id, so we can perform |
624 // the standard conversion. | 635 // the standard conversion. |
625 return ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId( | 636 return ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId( |
626 client_id); | 637 client_id); |
627 } | 638 } |
628 | 639 |
629 } // namespace content | 640 } // namespace content |
OLD | NEW |