| 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 |