| Index: content/browser/gpu/browser_gpu_memory_buffer_manager.cc
|
| diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
|
| index b6162ba5c4549fc2f22e1644687edb831b0c1828..23d2b50efd5179d06676a057e067b2238793b33a 100644
|
| --- a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
|
| +++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
|
| @@ -6,19 +6,118 @@
|
|
|
| #include "base/atomic_sequence_num.h"
|
| #include "base/bind.h"
|
| +#include "base/command_line.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/synchronization/waitable_event.h"
|
| #include "base/threading/thread_restrictions.h"
|
| #include "base/trace_event/process_memory_dump.h"
|
| #include "base/trace_event/trace_event.h"
|
| -#include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
|
| +#include "content/browser/gpu/gpu_process_host.h"
|
| #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
|
| #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
|
| +#include "content/common/gpu/gpu_memory_buffer_factory_shared_memory.h"
|
| #include "content/public/browser/browser_thread.h"
|
| +#include "content/public/common/content_switches.h"
|
| +#include "gpu/GLES2/gl2extchromium.h"
|
| +
|
| +#if defined(OS_MACOSX)
|
| +#include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h"
|
| +#endif
|
| +
|
| +#if defined(OS_ANDROID)
|
| +#include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h"
|
| +#endif
|
| +
|
| +#if defined(USE_OZONE)
|
| +#include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h"
|
| +#endif
|
|
|
| namespace content {
|
| namespace {
|
|
|
| +void GpuMemoryBufferDeleted(
|
| + scoped_refptr<base::SingleThreadTaskRunner> destruction_task_runner,
|
| + const GpuMemoryBufferImpl::DestructionCallback& destruction_callback,
|
| + uint32 sync_point) {
|
| + destruction_task_runner->PostTask(
|
| + FROM_HERE, base::Bind(destruction_callback, sync_point));
|
| +}
|
| +
|
| +bool IsGpuMemoryBufferFactoryConfigurationSupported(
|
| + gfx::GpuMemoryBufferType type,
|
| + const GpuMemoryBufferFactory::Configuration& configuration) {
|
| + switch (type) {
|
| + case gfx::SHARED_MEMORY_BUFFER:
|
| + return GpuMemoryBufferFactorySharedMemory::
|
| + IsGpuMemoryBufferConfigurationSupported(configuration.format,
|
| + configuration.usage);
|
| +#if defined(OS_MACOSX)
|
| + case gfx::IO_SURFACE_BUFFER:
|
| + return GpuMemoryBufferFactoryIOSurface::
|
| + IsGpuMemoryBufferConfigurationSupported(configuration.format,
|
| + configuration.usage);
|
| +#endif
|
| +#if defined(OS_ANDROID)
|
| + case gfx::SURFACE_TEXTURE_BUFFER:
|
| + return GpuMemoryBufferFactorySurfaceTexture::
|
| + IsGpuMemoryBufferConfigurationSupported(configuration.format,
|
| + configuration.usage);
|
| +#endif
|
| +#if defined(USE_OZONE)
|
| + case gfx::OZONE_NATIVE_BUFFER:
|
| + return GpuMemoryBufferFactoryOzoneNativeBuffer::
|
| + IsGpuMemoryBufferConfigurationSupported(configuration.format,
|
| + configuration.usage);
|
| +#endif
|
| + default:
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +gfx::GpuMemoryBufferType GetGpuMemoryBufferFactoryType() {
|
| + std::vector<gfx::GpuMemoryBufferType> supported_types;
|
| + GpuMemoryBufferFactory::GetSupportedTypes(&supported_types);
|
| + DCHECK(!supported_types.empty());
|
| +
|
| + // The GPU service will always use the preferred type.
|
| + return supported_types[0];
|
| +}
|
| +
|
| +std::vector<GpuMemoryBufferFactory::Configuration>
|
| +GetSupportedGpuMemoryBufferConfigurations(gfx::GpuMemoryBufferType type) {
|
| + std::vector<GpuMemoryBufferFactory::Configuration> configurations;
|
| + if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableNativeGpuMemoryBuffers)) {
|
| + const GpuMemoryBufferFactory::Configuration kNativeConfigurations[] = {
|
| + {gfx::GpuMemoryBuffer::R_8, gfx::GpuMemoryBuffer::MAP},
|
| + {gfx::GpuMemoryBuffer::R_8, gfx::GpuMemoryBuffer::PERSISTENT_MAP},
|
| + {gfx::GpuMemoryBuffer::RGBA_4444, gfx::GpuMemoryBuffer::MAP},
|
| + {gfx::GpuMemoryBuffer::RGBA_4444, gfx::GpuMemoryBuffer::PERSISTENT_MAP},
|
| + {gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::MAP},
|
| + {gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::PERSISTENT_MAP},
|
| + {gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::MAP},
|
| + {gfx::GpuMemoryBuffer::BGRA_8888,
|
| + gfx::GpuMemoryBuffer::PERSISTENT_MAP}};
|
| + for (auto& configuration : kNativeConfigurations) {
|
| + if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration))
|
| + configurations.push_back(configuration);
|
| + }
|
| + }
|
| +
|
| +#if defined(USE_OZONE)
|
| + const GpuMemoryBufferFactory::Configuration kScanoutConfigurations[] = {
|
| + {gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::SCANOUT},
|
| + {gfx::GpuMemoryBuffer::RGBX_8888, gfx::GpuMemoryBuffer::SCANOUT}};
|
| + for (auto& configuration : kScanoutConfigurations) {
|
| + if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration))
|
| + configurations.push_back(configuration);
|
| + }
|
| +#endif
|
| +
|
| + return configurations;
|
| +}
|
| +
|
| BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
|
|
|
| // Global atomic to generate gpu memory buffer unique IDs.
|
| @@ -50,11 +149,12 @@ struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest {
|
| scoped_ptr<gfx::GpuMemoryBuffer> result;
|
| };
|
|
|
| -BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(
|
| - GpuMemoryBufferFactoryHost* gpu_memory_buffer_factory_host,
|
| - int gpu_client_id)
|
| - : gpu_memory_buffer_factory_host_(gpu_memory_buffer_factory_host),
|
| +BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(int gpu_client_id)
|
| + : factory_type_(GetGpuMemoryBufferFactoryType()),
|
| + supported_configurations_(
|
| + GetSupportedGpuMemoryBufferConfigurations(factory_type_)),
|
| gpu_client_id_(gpu_client_id),
|
| + gpu_host_id_(0),
|
| weak_ptr_factory_(this) {
|
| DCHECK(!g_gpu_memory_buffer_manager);
|
| g_gpu_memory_buffer_manager = this;
|
| @@ -69,12 +169,38 @@ BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() {
|
| return g_gpu_memory_buffer_manager;
|
| }
|
|
|
| +// static
|
| +uint32 BrowserGpuMemoryBufferManager::GetImageTextureTarget(
|
| + gfx::GpuMemoryBuffer::Format format,
|
| + gfx::GpuMemoryBuffer::Usage usage) {
|
| + gfx::GpuMemoryBufferType type = GetGpuMemoryBufferFactoryType();
|
| + for (auto& configuration : GetSupportedGpuMemoryBufferConfigurations(type)) {
|
| + if (configuration.format != format || configuration.usage != usage)
|
| + continue;
|
| +
|
| + switch (type) {
|
| + case gfx::SURFACE_TEXTURE_BUFFER:
|
| + case gfx::OZONE_NATIVE_BUFFER:
|
| + // GPU memory buffers that are shared with the GL using EGLImages
|
| + // require TEXTURE_EXTERNAL_OES.
|
| + return GL_TEXTURE_EXTERNAL_OES;
|
| + case gfx::IO_SURFACE_BUFFER:
|
| + // IOSurface backed images require GL_TEXTURE_RECTANGLE_ARB.
|
| + return GL_TEXTURE_RECTANGLE_ARB;
|
| + default:
|
| + return GL_TEXTURE_2D;
|
| + }
|
| + }
|
| +
|
| + return GL_TEXTURE_2D;
|
| +}
|
| +
|
| scoped_ptr<gfx::GpuMemoryBuffer>
|
| BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
|
| const gfx::Size& size,
|
| gfx::GpuMemoryBuffer::Format format,
|
| gfx::GpuMemoryBuffer::Usage usage) {
|
| - return AllocateGpuMemoryBufferCommon(size, format, usage, 0);
|
| + return AllocateGpuMemoryBufferForSurface(size, format, usage, 0);
|
| }
|
|
|
| scoped_ptr<gfx::GpuMemoryBuffer>
|
| @@ -83,46 +209,10 @@ BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout(
|
| gfx::GpuMemoryBuffer::Format format,
|
| int32 surface_id) {
|
| DCHECK_GT(surface_id, 0);
|
| - return AllocateGpuMemoryBufferCommon(
|
| + return AllocateGpuMemoryBufferForSurface(
|
| size, format, gfx::GpuMemoryBuffer::SCANOUT, surface_id);
|
| }
|
|
|
| -scoped_ptr<gfx::GpuMemoryBuffer>
|
| -BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferCommon(
|
| - const gfx::Size& size,
|
| - gfx::GpuMemoryBuffer::Format format,
|
| - gfx::GpuMemoryBuffer::Usage usage,
|
| - int32 surface_id) {
|
| - DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| -
|
| - // Fallback to shared memory buffer if |format| and |usage| are not supported
|
| - // by factory.
|
| - if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
|
| - format, usage)) {
|
| - DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(format))
|
| - << format;
|
| - DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage)) << usage;
|
| - return GpuMemoryBufferImplSharedMemory::Create(
|
| - g_next_gpu_memory_buffer_id.GetNext(), size, format);
|
| - }
|
| -
|
| - AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_,
|
| - surface_id);
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO,
|
| - FROM_HERE,
|
| - base::Bind(&BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO,
|
| - base::Unretained(this), // Safe as we wait for result below.
|
| - base::Unretained(&request)));
|
| -
|
| - // We're blocking the UI thread, which is generally undesirable.
|
| - TRACE_EVENT0("browser",
|
| - "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer");
|
| - base::ThreadRestrictions::ScopedAllowWait allow_wait;
|
| - request.event.Wait();
|
| - return request.result.Pass();
|
| -}
|
| -
|
| void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
|
| const gfx::Size& size,
|
| gfx::GpuMemoryBuffer::Format format,
|
| @@ -134,39 +224,29 @@ void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
|
|
|
| gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext();
|
|
|
| - BufferMap& buffers = clients_[child_client_id];
|
| - DCHECK(buffers.find(new_id) == buffers.end());
|
| -
|
| - // Fallback to shared memory buffer if |format| and |usage| are not supported
|
| - // by factory.
|
| - if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
|
| - format, usage)) {
|
| - // Early out if we cannot fallback to shared memory buffer.
|
| - if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) ||
|
| - !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) ||
|
| - !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) {
|
| - callback.Run(gfx::GpuMemoryBufferHandle());
|
| - return;
|
| - }
|
| + // Use service side allocation if this is a supported configuration.
|
| + if (IsGpuMemoryBufferConfigurationSupported(format, usage)) {
|
| + AllocateGpuMemoryBufferOnIO(new_id, size, format, usage, child_client_id, 0,
|
| + false, callback);
|
| + return;
|
| + }
|
|
|
| - buffers[new_id] = BufferInfo(size, format, gfx::SHARED_MEMORY_BUFFER);
|
| - callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
|
| - new_id, size, format, child_process_handle));
|
| + // Early out if we cannot fallback to shared memory buffer.
|
| + if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) ||
|
| + !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) ||
|
| + !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) {
|
| + callback.Run(gfx::GpuMemoryBufferHandle());
|
| return;
|
| }
|
|
|
| - // Note: Handling of cases where the child process is removed before the
|
| - // allocation completes is less subtle if we set the buffer type to
|
| - // EMPTY_BUFFER here and verify that this has not changed when allocation
|
| - // completes.
|
| - buffers[new_id] = BufferInfo(size, format, gfx::EMPTY_BUFFER);
|
| -
|
| - gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
|
| - new_id, size, format, usage, child_client_id, 0,
|
| - base::Bind(&BrowserGpuMemoryBufferManager::
|
| - GpuMemoryBufferAllocatedForChildProcess,
|
| - weak_ptr_factory_.GetWeakPtr(), new_id, child_client_id,
|
| - callback));
|
| + BufferMap& buffers = clients_[child_client_id];
|
| + DCHECK(buffers.find(new_id) == buffers.end());
|
| +
|
| + // Allocate shared memory buffer as fallback.
|
| + buffers[new_id] =
|
| + BufferInfo(size, gfx::SHARED_MEMORY_BUFFER, format, usage, 0);
|
| + callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
|
| + new_id, size, format, child_process_handle));
|
| }
|
|
|
| gfx::GpuMemoryBuffer*
|
| @@ -219,32 +299,8 @@ void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
|
| int child_client_id,
|
| uint32 sync_point) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| - DCHECK(clients_.find(child_client_id) != clients_.end());
|
|
|
| - BufferMap& buffers = clients_[child_client_id];
|
| -
|
| - BufferMap::iterator buffer_it = buffers.find(id);
|
| - if (buffer_it == buffers.end()) {
|
| - LOG(ERROR) << "Invalid GpuMemoryBuffer ID for child process.";
|
| - return;
|
| - }
|
| -
|
| - // This can happen if a child process managed to trigger a call to this while
|
| - // a buffer is in the process of being allocated.
|
| - if (buffer_it->second.type == gfx::EMPTY_BUFFER) {
|
| - LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
|
| - return;
|
| - }
|
| -
|
| - // Buffers allocated using the factory need to be destroyed through the
|
| - // factory.
|
| - if (buffer_it->second.type != gfx::SHARED_MEMORY_BUFFER) {
|
| - gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
|
| - child_client_id,
|
| - sync_point);
|
| - }
|
| -
|
| - buffers.erase(buffer_it);
|
| + DestroyGpuMemoryBufferOnIO(id, child_client_id, sync_point);
|
| }
|
|
|
| void BrowserGpuMemoryBufferManager::ProcessRemoved(
|
| @@ -263,29 +319,87 @@ void BrowserGpuMemoryBufferManager::ProcessRemoved(
|
| if (buffer.second.type == gfx::EMPTY_BUFFER)
|
| continue;
|
|
|
| - // Skip shared memory buffers as they were not allocated using the factory.
|
| - if (buffer.second.type == gfx::SHARED_MEMORY_BUFFER)
|
| - continue;
|
| -
|
| - gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(buffer.first,
|
| - client_id, 0);
|
| + GpuProcessHost* host = GpuProcessHost::FromID(buffer.second.gpu_host_id);
|
| + if (host)
|
| + host->DestroyGpuMemoryBuffer(buffer.first, client_id, 0);
|
| }
|
|
|
| clients_.erase(client_it);
|
| }
|
|
|
| -void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
|
| +scoped_ptr<gfx::GpuMemoryBuffer>
|
| +BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface(
|
| + const gfx::Size& size,
|
| + gfx::GpuMemoryBuffer::Format format,
|
| + gfx::GpuMemoryBuffer::Usage usage,
|
| + int32 surface_id) {
|
| + DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| +
|
| + AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_,
|
| + surface_id);
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(
|
| + &BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO,
|
| + base::Unretained(this), // Safe as we wait for result below.
|
| + base::Unretained(&request)));
|
| +
|
| + // We're blocking the UI thread, which is generally undesirable.
|
| + TRACE_EVENT0(
|
| + "browser",
|
| + "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface");
|
| + base::ThreadRestrictions::ScopedAllowWait allow_wait;
|
| + request.event.Wait();
|
| + return request.result.Pass();
|
| +}
|
| +
|
| +bool BrowserGpuMemoryBufferManager::IsGpuMemoryBufferConfigurationSupported(
|
| + gfx::GpuMemoryBuffer::Format format,
|
| + gfx::GpuMemoryBuffer::Usage usage) const {
|
| + for (auto& configuration : supported_configurations_) {
|
| + if (configuration.format == format && configuration.usage == usage)
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO(
|
| AllocateGpuMemoryBufferRequest* request) {
|
| - // Note: Unretained is safe as this is only used for synchronous allocation
|
| - // from a non-IO thread.
|
| - gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
|
| - g_next_gpu_memory_buffer_id.GetNext(), request->size, request->format,
|
| - request->usage, request->client_id, request->surface_id,
|
| - base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO,
|
| - base::Unretained(this), base::Unretained(request)));
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext();
|
| +
|
| + // Use service side allocation if this is a supported configuration.
|
| + if (IsGpuMemoryBufferConfigurationSupported(request->format,
|
| + request->usage)) {
|
| + // Note: Unretained is safe as this is only used for synchronous allocation
|
| + // from a non-IO thread.
|
| + AllocateGpuMemoryBufferOnIO(
|
| + new_id, request->size, request->format, request->usage,
|
| + request->client_id, request->surface_id, false,
|
| + base::Bind(&BrowserGpuMemoryBufferManager::
|
| + GpuMemoryBufferAllocatedForSurfaceOnIO,
|
| + base::Unretained(this), base::Unretained(request)));
|
| + return;
|
| + }
|
| +
|
| + DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(request->format))
|
| + << request->format;
|
| + DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage))
|
| + << request->usage;
|
| +
|
| + BufferMap& buffers = clients_[request->client_id];
|
| + DCHECK(buffers.find(new_id) == buffers.end());
|
| +
|
| + // Allocate shared memory buffer as fallback.
|
| + buffers[new_id] = BufferInfo(request->size, gfx::SHARED_MEMORY_BUFFER,
|
| + request->format, request->usage, 0);
|
| + request->result = GpuMemoryBufferImplSharedMemory::Create(
|
| + new_id, request->size, request->format);
|
| + request->event.Signal();
|
| }
|
|
|
| -void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
|
| +void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForSurfaceOnIO(
|
| AllocateGpuMemoryBufferRequest* request,
|
| const gfx::GpuMemoryBufferHandle& handle) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| @@ -296,39 +410,85 @@ void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
|
| return;
|
| }
|
|
|
| - DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
|
| request->result = GpuMemoryBufferImpl::CreateFromHandle(
|
| handle, request->size, request->format, request->usage,
|
| - base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted,
|
| - weak_ptr_factory_.GetWeakPtr(), handle.id,
|
| - request->client_id));
|
| + base::Bind(
|
| + &GpuMemoryBufferDeleted,
|
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
|
| + base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO,
|
| + weak_ptr_factory_.GetWeakPtr(), handle.id,
|
| + request->client_id)));
|
| request->event.Signal();
|
| }
|
|
|
| -void BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted(
|
| +void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
|
| gfx::GpuMemoryBufferId id,
|
| + const gfx::Size& size,
|
| + gfx::GpuMemoryBuffer::Format format,
|
| + gfx::GpuMemoryBuffer::Usage usage,
|
| int client_id,
|
| - uint32 sync_point) {
|
| - gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
|
| - client_id,
|
| - sync_point);
|
| + int surface_id,
|
| + bool reused_gpu_process,
|
| + const AllocationCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + BufferMap& buffers = clients_[client_id];
|
| + DCHECK(buffers.find(id) == buffers.end());
|
| +
|
| + GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
|
| + if (!host) {
|
| + host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
|
| + CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE);
|
| + if (!host) {
|
| + LOG(ERROR) << "Failed to launch GPU process.";
|
| + callback.Run(gfx::GpuMemoryBufferHandle());
|
| + return;
|
| + }
|
| + gpu_host_id_ = host->host_id();
|
| + reused_gpu_process = false;
|
| + } else {
|
| + if (reused_gpu_process) {
|
| + // We come here if we retried to allocate the buffer because of a
|
| + // failure in GpuMemoryBufferAllocatedOnIO, but we ended up with the
|
| + // same process ID, meaning the failure was not because of a channel
|
| + // error, but another reason. So fail now.
|
| + LOG(ERROR) << "Failed to allocate GpuMemoryBuffer.";
|
| + callback.Run(gfx::GpuMemoryBufferHandle());
|
| + return;
|
| + }
|
| + reused_gpu_process = true;
|
| + }
|
| +
|
| + // Note: Handling of cases where the client is removed before the allocation
|
| + // completes is less subtle if we set the buffer type to EMPTY_BUFFER here
|
| + // and verify that this has not changed when allocation completes.
|
| + buffers[id] = BufferInfo(size, gfx::EMPTY_BUFFER, format, usage, 0);
|
| +
|
| + host->CreateGpuMemoryBuffer(
|
| + id, size, format, usage, client_id, surface_id,
|
| + base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO,
|
| + weak_ptr_factory_.GetWeakPtr(), id, client_id, surface_id,
|
| + gpu_host_id_, reused_gpu_process, callback));
|
| }
|
|
|
| -void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
|
| +void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
|
| gfx::GpuMemoryBufferId id,
|
| - int child_client_id,
|
| + int client_id,
|
| + int surface_id,
|
| + int gpu_host_id,
|
| + bool reused_gpu_process,
|
| const AllocationCallback& callback,
|
| const gfx::GpuMemoryBufferHandle& handle) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| - ClientMap::iterator client_it = clients_.find(child_client_id);
|
| + ClientMap::iterator client_it = clients_.find(client_id);
|
|
|
| - // This can happen if the child process is removed while the buffer is being
|
| - // allocated.
|
| + // This can happen if client is removed while the buffer is being allocated.
|
| if (client_it == clients_.end()) {
|
| if (!handle.is_null()) {
|
| - gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(
|
| - handle.id, child_client_id, 0);
|
| + GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id);
|
| + if (host)
|
| + host->DestroyGpuMemoryBuffer(handle.id, client_id, 0);
|
| }
|
| callback.Run(gfx::GpuMemoryBufferHandle());
|
| return;
|
| @@ -341,21 +501,69 @@ void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
|
| DCHECK_EQ(buffer_it->second.type, gfx::EMPTY_BUFFER);
|
|
|
| // If the handle isn't valid, that means that the GPU process crashed or is
|
| - // misbehaving so we remove the buffer entry and run the allocation callback
|
| - // with an empty handle to indicate failure.
|
| - bool valid_handle = !handle.is_null() && handle.id == id &&
|
| - handle.type != gfx::SHARED_MEMORY_BUFFER;
|
| + // misbehaving.
|
| + bool valid_handle = !handle.is_null() && handle.id == id;
|
| if (!valid_handle) {
|
| - buffers.erase(buffer_it);
|
| - callback.Run(gfx::GpuMemoryBufferHandle());
|
| + // If we failed after re-using the GPU process, it may have died in the
|
| + // mean time. Retry to have a chance to create a fresh GPU process.
|
| + if (handle.is_null() && reused_gpu_process) {
|
| + DVLOG(1) << "Failed to create buffer through existing GPU process. "
|
| + "Trying to restart GPU process.";
|
| + // If the GPU process has already been restarted, retry without failure
|
| + // when GPU process host ID already exists.
|
| + if (gpu_host_id != gpu_host_id_)
|
| + reused_gpu_process = false;
|
| + gfx::Size size = buffer_it->second.size;
|
| + gfx::GpuMemoryBuffer::Format format = buffer_it->second.format;
|
| + gfx::GpuMemoryBuffer::Usage usage = buffer_it->second.usage;
|
| + // Remove the buffer entry and call AllocateGpuMemoryBufferOnIO again.
|
| + buffers.erase(buffer_it);
|
| + AllocateGpuMemoryBufferOnIO(id, size, format, usage, client_id,
|
| + surface_id, reused_gpu_process, callback);
|
| + } else {
|
| + // Remove the buffer entry and run the allocation callback with an empty
|
| + // handle to indicate failure.
|
| + buffers.erase(buffer_it);
|
| + callback.Run(gfx::GpuMemoryBufferHandle());
|
| + }
|
| return;
|
| }
|
|
|
| - // Store the type of this buffer so it can be cleaned up if the child
|
| - // process is removed.
|
| + // Store the type and host id of this buffer so it can be cleaned up if the
|
| + // client is removed.
|
| buffer_it->second.type = handle.type;
|
| + buffer_it->second.gpu_host_id = gpu_host_id;
|
|
|
| callback.Run(handle);
|
| }
|
|
|
| +void BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO(
|
| + gfx::GpuMemoryBufferId id,
|
| + int client_id,
|
| + uint32 sync_point) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK(clients_.find(client_id) != clients_.end());
|
| +
|
| + BufferMap& buffers = clients_[client_id];
|
| +
|
| + BufferMap::iterator buffer_it = buffers.find(id);
|
| + if (buffer_it == buffers.end()) {
|
| + LOG(ERROR) << "Invalid GpuMemoryBuffer ID for client.";
|
| + return;
|
| + }
|
| +
|
| + // This can happen if a client managed to call this while a buffer is in the
|
| + // process of being allocated.
|
| + if (buffer_it->second.type == gfx::EMPTY_BUFFER) {
|
| + LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
|
| + return;
|
| + }
|
| +
|
| + GpuProcessHost* host = GpuProcessHost::FromID(buffer_it->second.gpu_host_id);
|
| + if (host)
|
| + host->DestroyGpuMemoryBuffer(id, client_id, sync_point);
|
| +
|
| + buffers.erase(buffer_it);
|
| +}
|
| +
|
| } // namespace content
|
|
|