Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1367)

Unified Diff: content/browser/gpu/browser_gpu_memory_buffer_manager.cc

Issue 1189943002: content: Fix lost context handling when using native GpuMemoryBuffers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: retry logic and remove singleton Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698