| 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_tracing_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 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration)) | 130 if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration)) |
| 130 configurations.push_back(configuration); | 131 configurations.push_back(configuration); |
| 131 } | 132 } |
| 132 #endif | 133 #endif |
| 133 | 134 |
| 134 return configurations; | 135 return configurations; |
| 135 } | 136 } |
| 136 | 137 |
| 137 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr; | 138 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr; |
| 138 | 139 |
| 139 // Global atomic to generate gpu memory buffer unique IDs. | |
| 140 base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id; | |
| 141 | |
| 142 } // namespace | 140 } // namespace |
| 143 | 141 |
| 144 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest { | 142 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest { |
| 145 AllocateGpuMemoryBufferRequest(const gfx::Size& size, | 143 AllocateGpuMemoryBufferRequest(const gfx::Size& size, |
| 146 gfx::BufferFormat format, | 144 gfx::BufferFormat format, |
| 147 gfx::BufferUsage usage, | 145 gfx::BufferUsage usage, |
| 148 int client_id, | 146 int client_id, |
| 149 int surface_id) | 147 int surface_id) |
| 150 : event(true, false), | 148 : event(true, false), |
| 151 size(size), | 149 size(size), |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout( | 220 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout( |
| 223 const gfx::Size& size, | 221 const gfx::Size& size, |
| 224 gfx::BufferFormat format, | 222 gfx::BufferFormat format, |
| 225 int32 surface_id) { | 223 int32 surface_id) { |
| 226 DCHECK_GT(surface_id, 0); | 224 DCHECK_GT(surface_id, 0); |
| 227 return AllocateGpuMemoryBufferForSurface( | 225 return AllocateGpuMemoryBufferForSurface( |
| 228 size, format, gfx::BufferUsage::SCANOUT, surface_id); | 226 size, format, gfx::BufferUsage::SCANOUT, surface_id); |
| 229 } | 227 } |
| 230 | 228 |
| 231 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess( | 229 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess( |
| 230 gfx::GpuMemoryBufferId id, |
| 232 const gfx::Size& size, | 231 const gfx::Size& size, |
| 233 gfx::BufferFormat format, | 232 gfx::BufferFormat format, |
| 234 gfx::BufferUsage usage, | 233 gfx::BufferUsage usage, |
| 235 base::ProcessHandle child_process_handle, | 234 base::ProcessHandle child_process_handle, |
| 236 int child_client_id, | 235 int child_client_id, |
| 237 const AllocationCallback& callback) { | 236 const AllocationCallback& callback) { |
| 238 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 237 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 239 | 238 |
| 240 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext(); | |
| 241 | |
| 242 // Use service side allocation if this is a supported configuration. | 239 // Use service side allocation if this is a supported configuration. |
| 243 if (IsGpuMemoryBufferConfigurationSupported(format, usage)) { | 240 if (IsGpuMemoryBufferConfigurationSupported(format, usage)) { |
| 244 AllocateGpuMemoryBufferOnIO(new_id, size, format, usage, child_client_id, 0, | 241 AllocateGpuMemoryBufferOnIO(id, size, format, usage, child_client_id, 0, |
| 245 false, callback); | 242 false, callback); |
| 246 return; | 243 return; |
| 247 } | 244 } |
| 248 | 245 |
| 249 // Early out if we cannot fallback to shared memory buffer. | 246 // Early out if we cannot fallback to shared memory buffer. |
| 250 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) || | 247 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) || |
| 251 !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) || | 248 !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) || |
| 252 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) { | 249 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) { |
| 253 callback.Run(gfx::GpuMemoryBufferHandle()); | 250 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 254 return; | 251 return; |
| 255 } | 252 } |
| 256 | 253 |
| 257 BufferMap& buffers = clients_[child_client_id]; | 254 BufferMap& buffers = clients_[child_client_id]; |
| 258 DCHECK(buffers.find(new_id) == buffers.end()); | |
| 259 | 255 |
| 260 // Allocate shared memory buffer as fallback. | 256 // Allocate shared memory buffer as fallback. |
| 261 buffers[new_id] = | 257 if (!buffers.insert( |
| 262 BufferInfo(size, gfx::SHARED_MEMORY_BUFFER, format, usage, 0); | 258 std::make_pair(id, BufferInfo(size, gfx::SHARED_MEMORY_BUFFER, |
| 259 format, usage, 0))) |
| 260 .second) { |
| 261 LOG(ERROR) << "Child process attempted to allocate a GpuMemoryBuffer with " |
| 262 "an existing ID."; |
| 263 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 264 return; |
| 265 } |
| 266 |
| 263 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( | 267 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( |
| 264 new_id, size, format, child_process_handle)); | 268 id, size, format, child_process_handle)); |
| 265 } | 269 } |
| 266 | 270 |
| 267 gfx::GpuMemoryBuffer* | 271 gfx::GpuMemoryBuffer* |
| 268 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer( | 272 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer( |
| 269 ClientBuffer buffer) { | 273 ClientBuffer buffer) { |
| 270 return GpuMemoryBufferImpl::FromClientBuffer(buffer); | 274 return GpuMemoryBufferImpl::FromClientBuffer(buffer); |
| 271 } | 275 } |
| 272 | 276 |
| 273 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint( | 277 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint( |
| 274 gfx::GpuMemoryBuffer* buffer, | 278 gfx::GpuMemoryBuffer* buffer, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 285 for (const auto& client : clients_) { | 289 for (const auto& client : clients_) { |
| 286 int client_id = client.first; | 290 int client_id = client.first; |
| 287 | 291 |
| 288 for (const auto& buffer : client.second) { | 292 for (const auto& buffer : client.second) { |
| 289 if (buffer.second.type == gfx::EMPTY_BUFFER) | 293 if (buffer.second.type == gfx::EMPTY_BUFFER) |
| 290 continue; | 294 continue; |
| 291 | 295 |
| 292 gfx::GpuMemoryBufferId buffer_id = buffer.first; | 296 gfx::GpuMemoryBufferId buffer_id = buffer.first; |
| 293 base::trace_event::MemoryAllocatorDump* dump = | 297 base::trace_event::MemoryAllocatorDump* dump = |
| 294 pmd->CreateAllocatorDump(base::StringPrintf( | 298 pmd->CreateAllocatorDump(base::StringPrintf( |
| 295 "gpumemorybuffer/client_%d/buffer_%d", client_id, buffer_id)); | 299 "gpumemorybuffer/client_%d/buffer_%d", client_id, buffer_id.id)); |
| 296 if (!dump) | 300 if (!dump) |
| 297 return false; | 301 return false; |
| 298 | 302 |
| 299 size_t buffer_size_in_bytes = 0; | 303 size_t buffer_size_in_bytes = 0; |
| 300 // Note: BufferSizeInBytes returns an approximated size for the buffer | 304 // Note: BufferSizeInBytes returns an approximated size for the buffer |
| 301 // but the factory can be made to return the exact size if this | 305 // but the factory can be made to return the exact size if this |
| 302 // approximation is not good enough. | 306 // approximation is not good enough. |
| 303 bool valid_size = GpuMemoryBufferImpl::BufferSizeInBytes( | 307 bool valid_size = GpuMemoryBufferImpl::BufferSizeInBytes( |
| 304 buffer.second.size, buffer.second.format, &buffer_size_in_bytes); | 308 buffer.second.size, buffer.second.format, &buffer_size_in_bytes); |
| 305 DCHECK(valid_size); | 309 DCHECK(valid_size); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 if (configuration.format == format && configuration.usage == usage) | 396 if (configuration.format == format && configuration.usage == usage) |
| 393 return true; | 397 return true; |
| 394 } | 398 } |
| 395 return false; | 399 return false; |
| 396 } | 400 } |
| 397 | 401 |
| 398 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO( | 402 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO( |
| 399 AllocateGpuMemoryBufferRequest* request) { | 403 AllocateGpuMemoryBufferRequest* request) { |
| 400 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 404 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 401 | 405 |
| 402 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext(); | 406 gfx::GpuMemoryBufferId new_id = |
| 407 content::GetNextGenericSharedMemoryTracingId(); |
| 403 | 408 |
| 404 // Use service side allocation if this is a supported configuration. | 409 // Use service side allocation if this is a supported configuration. |
| 405 if (IsGpuMemoryBufferConfigurationSupported(request->format, | 410 if (IsGpuMemoryBufferConfigurationSupported(request->format, |
| 406 request->usage)) { | 411 request->usage)) { |
| 407 // Note: Unretained is safe as this is only used for synchronous allocation | 412 // Note: Unretained is safe as this is only used for synchronous allocation |
| 408 // from a non-IO thread. | 413 // from a non-IO thread. |
| 409 AllocateGpuMemoryBufferOnIO( | 414 AllocateGpuMemoryBufferOnIO( |
| 410 new_id, request->size, request->format, request->usage, | 415 new_id, request->size, request->format, request->usage, |
| 411 request->client_id, request->surface_id, false, | 416 request->client_id, request->surface_id, false, |
| 412 base::Bind(&BrowserGpuMemoryBufferManager:: | 417 base::Bind(&BrowserGpuMemoryBufferManager:: |
| 413 GpuMemoryBufferAllocatedForSurfaceOnIO, | 418 GpuMemoryBufferAllocatedForSurfaceOnIO, |
| 414 base::Unretained(this), base::Unretained(request))); | 419 base::Unretained(this), base::Unretained(request))); |
| 415 return; | 420 return; |
| 416 } | 421 } |
| 417 | 422 |
| 418 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(request->format)) | 423 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(request->format)) |
| 419 << static_cast<int>(request->format); | 424 << static_cast<int>(request->format); |
| 420 DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage)) | 425 DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage)) |
| 421 << static_cast<int>(request->usage); | 426 << static_cast<int>(request->usage); |
| 422 | 427 |
| 423 BufferMap& buffers = clients_[request->client_id]; | 428 BufferMap& buffers = clients_[request->client_id]; |
| 424 DCHECK(buffers.find(new_id) == buffers.end()); | |
| 425 | 429 |
| 426 // Allocate shared memory buffer as fallback. | 430 // Allocate shared memory buffer as fallback. |
| 427 buffers[new_id] = BufferInfo(request->size, gfx::SHARED_MEMORY_BUFFER, | 431 bool insert_succeeded = |
| 428 request->format, request->usage, 0); | 432 buffers.insert(std::make_pair( |
| 433 new_id, |
| 434 BufferInfo(request->size, gfx::SHARED_MEMORY_BUFFER, |
| 435 request->format, request->usage, 0))) |
| 436 .second; |
| 437 DCHECK(insert_succeeded); |
| 438 |
| 429 // 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 |
| 430 // destroyed. | 440 // destroyed. |
| 431 request->result = GpuMemoryBufferImplSharedMemory::Create( | 441 request->result = GpuMemoryBufferImplSharedMemory::Create( |
| 432 new_id, request->size, request->format, | 442 new_id, request->size, request->format, |
| 433 base::Bind( | 443 base::Bind( |
| 434 &GpuMemoryBufferDeleted, | 444 &GpuMemoryBufferDeleted, |
| 435 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), | 445 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), |
| 436 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO, | 446 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO, |
| 437 base::Unretained(this), new_id, request->client_id))); | 447 base::Unretained(this), new_id, request->client_id))); |
| 438 request->event.Signal(); | 448 request->event.Signal(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 465 gfx::GpuMemoryBufferId id, | 475 gfx::GpuMemoryBufferId id, |
| 466 const gfx::Size& size, | 476 const gfx::Size& size, |
| 467 gfx::BufferFormat format, | 477 gfx::BufferFormat format, |
| 468 gfx::BufferUsage usage, | 478 gfx::BufferUsage usage, |
| 469 int client_id, | 479 int client_id, |
| 470 int surface_id, | 480 int surface_id, |
| 471 bool reused_gpu_process, | 481 bool reused_gpu_process, |
| 472 const AllocationCallback& callback) { | 482 const AllocationCallback& callback) { |
| 473 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 483 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 474 | 484 |
| 475 BufferMap& buffers = clients_[client_id]; | |
| 476 DCHECK(buffers.find(id) == buffers.end()); | |
| 477 | |
| 478 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); | 485 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); |
| 479 if (!host) { | 486 if (!host) { |
| 480 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, | 487 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, |
| 481 CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE); | 488 CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE); |
| 482 if (!host) { | 489 if (!host) { |
| 483 LOG(ERROR) << "Failed to launch GPU process."; | 490 LOG(ERROR) << "Failed to launch GPU process."; |
| 484 callback.Run(gfx::GpuMemoryBufferHandle()); | 491 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 485 return; | 492 return; |
| 486 } | 493 } |
| 487 gpu_host_id_ = host->host_id(); | 494 gpu_host_id_ = host->host_id(); |
| 488 reused_gpu_process = false; | 495 reused_gpu_process = false; |
| 489 } else { | 496 } else { |
| 490 if (reused_gpu_process) { | 497 if (reused_gpu_process) { |
| 491 // 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 |
| 492 // failure in GpuMemoryBufferAllocatedOnIO, but we ended up with the | 499 // failure in GpuMemoryBufferAllocatedOnIO, but we ended up with the |
| 493 // 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 |
| 494 // error, but another reason. So fail now. | 501 // error, but another reason. So fail now. |
| 495 LOG(ERROR) << "Failed to allocate GpuMemoryBuffer."; | 502 LOG(ERROR) << "Failed to allocate GpuMemoryBuffer."; |
| 496 callback.Run(gfx::GpuMemoryBufferHandle()); | 503 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 497 return; | 504 return; |
| 498 } | 505 } |
| 499 reused_gpu_process = true; | 506 reused_gpu_process = true; |
| 500 } | 507 } |
| 501 | 508 |
| 509 BufferMap& buffers = clients_[client_id]; |
| 510 |
| 502 // 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 |
| 503 // 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 |
| 504 // and verify that this has not changed when allocation completes. | 513 // and verify that this has not changed when allocation completes. |
| 505 buffers[id] = BufferInfo(size, gfx::EMPTY_BUFFER, format, usage, 0); | 514 if (!buffers.insert(std::make_pair(id, BufferInfo(size, gfx::EMPTY_BUFFER, |
| 515 format, usage, 0))) |
| 516 .second) { |
| 517 LOG(ERROR) << "Child process attempted to allocate a GpuMemoryBuffer with " |
| 518 "an existing ID."; |
| 519 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 520 return; |
| 521 } |
| 506 | 522 |
| 507 // 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 |
| 508 // destroyed. | 524 // destroyed. |
| 509 host->CreateGpuMemoryBuffer( | 525 host->CreateGpuMemoryBuffer( |
| 510 id, size, format, usage, client_id, surface_id, | 526 id, size, format, usage, client_id, surface_id, |
| 511 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO, | 527 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO, |
| 512 base::Unretained(this), id, client_id, surface_id, | 528 base::Unretained(this), id, client_id, surface_id, |
| 513 gpu_host_id_, reused_gpu_process, callback)); | 529 gpu_host_id_, reused_gpu_process, callback)); |
| 514 } | 530 } |
| 515 | 531 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 return gpu_client_tracing_id_; | 631 return gpu_client_tracing_id_; |
| 616 } | 632 } |
| 617 | 633 |
| 618 // 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 |
| 619 // the standard conversion. | 635 // the standard conversion. |
| 620 return ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId( | 636 return ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId( |
| 621 client_id); | 637 client_id); |
| 622 } | 638 } |
| 623 | 639 |
| 624 } // namespace content | 640 } // namespace content |
| OLD | NEW |