summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-22 23:13:09 +0000
committerreveman@chromium.org <reveman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-22 23:13:09 +0000
commitbc10f46abc6b4d6338fd1819b0360bc9115846f2 (patch)
tree34595adeaffa513af37b0caa4e9afd05cfcf65d0
parent9f67dd0edac097ff862e9f92e988da2f5cb19348 (diff)
downloadchromium_src-bc10f46abc6b4d6338fd1819b0360bc9115846f2.zip
chromium_src-bc10f46abc6b4d6338fd1819b0360bc9115846f2.tar.gz
chromium_src-bc10f46abc6b4d6338fd1819b0360bc9115846f2.tar.bz2
Add multi-process GpuMemoryBuffer framework.
This adds a multi-process framework for reading/writing directly to memory that the 3D graphics hardware can use for rendering without any costly copying having to be done on the GPU process side. A GpuMemoryBuffer is a type of shared memory that can be accessed by the GPU. The high level procedure required to allocate this type of memory is almost exactly the same as that for standard shared memory. Only the browser process can allocated the memory and it needs to be shared and registered with the GPU process before it can be used. This also adds a GpuMemoryBuffer type that is backed by standard shared memory for testing purposes. TEST=gpu_unittests --gtest_filter=MockGpuMemoryBufferTest.Lifecycle BUG=261649 Review URL: https://codereview.chromium.org/19762004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230248 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/gpu/browser_gpu_channel_host_factory.cc24
-rw-r--r--content/browser/gpu/browser_gpu_channel_host_factory.h4
-rw-r--r--content/browser/renderer_host/render_message_filter.cc21
-rw-r--r--content/browser/renderer_host/render_message_filter.h4
-rw-r--r--content/common/child_process_host_impl.cc9
-rw-r--r--content/common/child_process_host_impl.h6
-rw-r--r--content/common/child_process_messages.h13
-rw-r--r--content/common/gpu/client/command_buffer_proxy_impl.cc54
-rw-r--r--content/common/gpu/client/command_buffer_proxy_impl.h9
-rw-r--r--content/common/gpu/client/gpu_channel_host.cc31
-rw-r--r--content/common/gpu/client/gpu_channel_host.h22
-rw-r--r--content/common/gpu/client/gpu_memory_buffer_impl.cc80
-rw-r--r--content/common/gpu/client/gpu_memory_buffer_impl.h45
-rw-r--r--content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc19
-rw-r--r--content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h9
-rw-r--r--content/common/gpu/gpu_command_buffer_stub.cc34
-rw-r--r--content/common/gpu/gpu_command_buffer_stub.h10
-rw-r--r--content/common/gpu/gpu_messages.h16
-rw-r--r--content/content_common.gypi2
-rw-r--r--content/renderer/render_thread_impl.cc42
-rw-r--r--content/renderer/render_thread_impl.h4
21 files changed, 451 insertions, 7 deletions
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index 7bc6fca..2f04189 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -9,8 +9,9 @@
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
-#include "content/common/gpu/gpu_messages.h"
#include "content/common/child_process_host_impl.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+#include "content/common/gpu/gpu_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_client.h"
#include "ipc/ipc_forwarding_message_filter.h"
@@ -284,6 +285,27 @@ GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
return gpu_channel_.get();
}
+scoped_ptr<gfx::GpuMemoryBuffer>
+ BrowserGpuChannelHostFactory::AllocateGpuMemoryBuffer(
+ size_t width,
+ size_t height,
+ unsigned internalformat) {
+ if (!GpuMemoryBufferImpl::IsFormatValid(internalformat))
+ return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+ size_t size = width * height *
+ GpuMemoryBufferImpl::BytesPerPixel(internalformat);
+ scoped_ptr<base::SharedMemory> shm(new base::SharedMemory());
+ if (!shm->CreateAnonymous(size))
+ return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+ return make_scoped_ptr<gfx::GpuMemoryBuffer>(
+ new GpuMemoryBufferImpl(shm.Pass(),
+ width,
+ height,
+ internalformat));
+}
+
// static
void BrowserGpuChannelHostFactory::AddFilterOnIO(
int host_id,
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.h b/content/browser/gpu/browser_gpu_channel_host_factory.h
index ca31183..0e10ece 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.h
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.h
@@ -38,6 +38,10 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
virtual void DeleteImage(int32 image_idu, int32 sync_point) OVERRIDE;
virtual GpuChannelHost* EstablishGpuChannelSync(
CauseForGpuLaunch cause_for_gpu_launch) OVERRIDE;
+ virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+ size_t width,
+ size_t height,
+ unsigned internalformat) OVERRIDE;
// Specify a task runner and callback to be used for a set of messages. The
// callback will be set up on the current GpuProcessHost, identified by
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index d7e32d0..7fd1870 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -398,6 +398,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message,
OnCheckNotificationPermission)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory,
OnAllocateSharedMemory)
+ IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
+ OnAllocateGpuMemoryBuffer)
#if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(ViewHostMsg_AllocTransportDIB, OnAllocTransportDIB)
IPC_MESSAGE_HANDLER(ViewHostMsg_FreeTransportDIB, OnFreeTransportDIB)
@@ -1165,4 +1167,23 @@ void RenderMessageFilter::OnWebAudioMediaCodec(
true);
}
#endif
+
+void RenderMessageFilter::OnAllocateGpuMemoryBuffer(
+ uint32 buffer_size,
+ gfx::GpuMemoryBufferHandle* handle) {
+ // TODO(reveman): Implement allocation of real GpuMemoryBuffer.
+ // Currently this function creates a fake GpuMemoryBuffer that is
+ // backed by shared memory and requires an upload before it can
+ // be used as a texture. The plan is to instead have this function
+ // allocate a real GpuMemoryBuffer in whatever form is supported
+ // by platform and drivers.
+ //
+ // Note: |buffer_size| likely needs to be replaced by a more
+ // specific buffer description but is enough for the shared memory
+ // backed GpuMemoryBuffer currently returned.
+ handle->type = gfx::SHARED_MEMORY_BUFFER;
+ ChildProcessHostImpl::AllocateSharedMemory(
+ buffer_size, PeerHandle(), &handle->handle);
+}
+
} // namespace content
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 446a531..d0a4386 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -52,6 +52,7 @@ class TaskRunner;
namespace gfx {
class Rect;
+struct GpuMemoryBufferHandle;
}
namespace media {
@@ -261,6 +262,9 @@ class RenderMessageFilter : public BrowserMessageFilter {
uint32_t data_size);
#endif
+ void OnAllocateGpuMemoryBuffer(uint32 buffer_size,
+ gfx::GpuMemoryBufferHandle* handle);
+
// Cached resource request dispatcher host and plugin service, guaranteed to
// be non-null if Init succeeds. We do not own the objects, they are managed
// by the BrowserProcess, which has a wider scope than we do.
diff --git a/content/common/child_process_host_impl.cc b/content/common/child_process_host_impl.cc
index fb058d3..a2f40d4 100644
--- a/content/common/child_process_host_impl.cc
+++ b/content/common/child_process_host_impl.cc
@@ -247,6 +247,8 @@ bool ChildProcessHostImpl::OnMessageReceived(const IPC::Message& msg) {
OnShutdownRequest)
IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateSharedMemory,
OnAllocateSharedMemory)
+ IPC_MESSAGE_HANDLER(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
+ OnAllocateGpuMemoryBuffer)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -293,4 +295,11 @@ void ChildProcessHostImpl::OnShutdownRequest() {
Send(new ChildProcessMsg_Shutdown());
}
+void ChildProcessHostImpl::OnAllocateGpuMemoryBuffer(
+ uint32 buffer_size,
+ gfx::GpuMemoryBufferHandle* handle) {
+ handle->type = gfx::SHARED_MEMORY_BUFFER;
+ AllocateSharedMemory(buffer_size, peer_handle_, &handle->handle);
+}
+
} // namespace content
diff --git a/content/common/child_process_host_impl.h b/content/common/child_process_host_impl.h
index a24f3b8..74700bc 100644
--- a/content/common/child_process_host_impl.h
+++ b/content/common/child_process_host_impl.h
@@ -22,6 +22,10 @@ namespace base {
class FilePath;
}
+namespace gfx {
+struct GpuMemoryBufferHandle;
+}
+
namespace content {
class ChildProcessHostDelegate;
@@ -75,6 +79,8 @@ class CONTENT_EXPORT ChildProcessHostImpl : public ChildProcessHost,
void OnShutdownRequest();
void OnAllocateSharedMemory(uint32 buffer_size,
base::SharedMemoryHandle* handle);
+ void OnAllocateGpuMemoryBuffer(uint32 buffer_size,
+ gfx::GpuMemoryBufferHandle* handle);
ChildProcessHostDelegate* delegate_;
base::ProcessHandle peer_handle_;
diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h
index 3f70bc3..c122588 100644
--- a/content/common/child_process_messages.h
+++ b/content/common/child_process_messages.h
@@ -13,6 +13,7 @@
#include "base/values.h"
#include "content/common/content_export.h"
#include "ipc/ipc_message_macros.h"
+#include "ui/gfx/gpu_memory_buffer.h"
IPC_ENUM_TRAITS(tracked_objects::ThreadData::Status)
@@ -54,6 +55,13 @@ IPC_STRUCT_TRAITS_BEGIN(tracked_objects::ProcessDataSnapshot)
IPC_STRUCT_TRAITS_MEMBER(process_id)
IPC_STRUCT_TRAITS_END()
+IPC_ENUM_TRAITS(gfx::GpuMemoryBufferType)
+
+IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
+ IPC_STRUCT_TRAITS_MEMBER(type)
+ IPC_STRUCT_TRAITS_MEMBER(handle)
+IPC_STRUCT_TRAITS_END()
+
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
@@ -138,3 +146,8 @@ IPC_SYNC_MESSAGE_CONTROL1_1(ChildProcessHostMsg_SyncAllocateSharedMemory,
IPC_MESSAGE_CONTROL1(ChildProcessHostMsg_TcmallocStats,
std::string /* output */)
#endif
+
+// Asks the browser to create a gpu memory buffer.
+IPC_SYNC_MESSAGE_CONTROL1_1(ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer,
+ uint32 /* buffer size */,
+ gfx::GpuMemoryBufferHandle)
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.cc b/content/common/gpu/client/command_buffer_proxy_impl.cc
index 94abbe1..3fbe537 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.cc
+++ b/content/common/gpu/client/command_buffer_proxy_impl.cc
@@ -367,7 +367,7 @@ void CommandBufferProxyImpl::SetContextLostReason(
}
bool CommandBufferProxyImpl::SupportsGpuMemoryBuffer() {
- return false;
+ return true;
}
gfx::GpuMemoryBuffer* CommandBufferProxyImpl::CreateGpuMemoryBuffer(
@@ -375,12 +375,58 @@ gfx::GpuMemoryBuffer* CommandBufferProxyImpl::CreateGpuMemoryBuffer(
size_t height,
unsigned internalformat,
int32* id) {
- NOTREACHED();
- return NULL;
+ *id = -1;
+
+ if (last_state_.error != gpu::error::kNoError)
+ return NULL;
+
+ int32 new_id = channel_->ReserveGpuMemoryBufferId();
+ DCHECK(gpu_memory_buffers_.find(new_id) == gpu_memory_buffers_.end());
+
+ scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer(
+ channel_->factory()->AllocateGpuMemoryBuffer(width,
+ height,
+ internalformat));
+ if (!gpu_memory_buffer)
+ return NULL;
+
+ DCHECK(GpuChannelHost::IsValidGpuMemoryBuffer(
+ gpu_memory_buffer->GetHandle()));
+
+ // This handle is owned by the GPU process and must be passed to it or it
+ // will leak. In otherwords, do not early out on error between here and the
+ // sending of the RegisterGpuMemoryBuffer IPC below.
+ gfx::GpuMemoryBufferHandle handle =
+ channel_->ShareGpuMemoryBufferToGpuProcess(
+ gpu_memory_buffer->GetHandle());
+
+ if (!Send(new GpuCommandBufferMsg_RegisterGpuMemoryBuffer(
+ route_id_,
+ new_id,
+ handle,
+ width,
+ height,
+ internalformat))) {
+ return NULL;
+ }
+
+ *id = new_id;
+ gpu_memory_buffers_[new_id] = gpu_memory_buffer.release();
+ return gpu_memory_buffers_[new_id];
}
void CommandBufferProxyImpl::DestroyGpuMemoryBuffer(int32 id) {
- NOTREACHED();
+ if (last_state_.error != gpu::error::kNoError)
+ return;
+
+ // Remove the gpu memory buffer from the client side cache.
+ GpuMemoryBufferMap::iterator it = gpu_memory_buffers_.find(id);
+ if (it != gpu_memory_buffers_.end()) {
+ delete it->second;
+ gpu_memory_buffers_.erase(it);
+ }
+
+ Send(new GpuCommandBufferMsg_DestroyGpuMemoryBuffer(route_id_, id));
}
int CommandBufferProxyImpl::GetRouteID() const {
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h
index c891483..35255a9 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -16,7 +16,6 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "content/common/gpu/gpu_memory_allocation.h"
-#include "content/common/gpu/gpu_memory_allocation.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "gpu/command_buffer/common/command_buffer_shared.h"
#include "gpu/command_buffer/common/gpu_control.h"
@@ -30,6 +29,10 @@ namespace base {
class SharedMemory;
}
+namespace gfx {
+class GpuMemoryBuffer;
+}
+
namespace gpu {
struct Mailbox;
}
@@ -145,6 +148,7 @@ class CommandBufferProxyImpl
private:
typedef std::map<int32, gpu::Buffer> TransferBufferMap;
typedef base::hash_map<uint32, base::Closure> SignalTaskMap;
+ typedef std::map<int32, gfx::GpuMemoryBuffer*> GpuMemoryBufferMap;
// Send an IPC message over the GPU channel. This is private to fully
// encapsulate the channel; all callers of this function must explicitly
@@ -202,6 +206,9 @@ class CommandBufferProxyImpl
uint32 next_signal_id_;
SignalTaskMap signal_tasks_;
+ // Local cache of id to gpu memory buffer mapping.
+ GpuMemoryBufferMap gpu_memory_buffers_;
+
DISALLOW_COPY_AND_ASSIGN(CommandBufferProxyImpl);
};
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 27c71de..4624ec7 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -46,6 +46,17 @@ scoped_refptr<GpuChannelHost> GpuChannelHost::Create(
return host;
}
+// static
+bool GpuChannelHost::IsValidGpuMemoryBuffer(
+ gfx::GpuMemoryBufferHandle handle) {
+ switch (handle.type) {
+ case gfx::SHARED_MEMORY_BUFFER:
+ return true;
+ default:
+ return false;
+ }
+}
+
GpuChannelHost::GpuChannelHost(GpuChannelHostFactory* factory,
int gpu_host_id,
int client_id,
@@ -55,6 +66,7 @@ GpuChannelHost::GpuChannelHost(GpuChannelHostFactory* factory,
gpu_host_id_(gpu_host_id),
gpu_info_(gpu_info) {
next_transfer_buffer_id_.GetNext();
+ next_gpu_memory_buffer_id_.GetNext();
}
void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle) {
@@ -285,6 +297,25 @@ int32 GpuChannelHost::ReserveTransferBufferId() {
return next_transfer_buffer_id_.GetNext();
}
+gfx::GpuMemoryBufferHandle GpuChannelHost::ShareGpuMemoryBufferToGpuProcess(
+ gfx::GpuMemoryBufferHandle source_handle) {
+ switch (source_handle.type) {
+ case gfx::SHARED_MEMORY_BUFFER: {
+ gfx::GpuMemoryBufferHandle handle;
+ handle.type = gfx::SHARED_MEMORY_BUFFER;
+ handle.handle = ShareToGpuProcess(source_handle.handle);
+ return handle;
+ }
+ default:
+ NOTREACHED();
+ return gfx::GpuMemoryBufferHandle();
+ }
+}
+
+int32 GpuChannelHost::ReserveGpuMemoryBufferId() {
+ return next_gpu_memory_buffer_id_.GetNext();
+}
+
GpuChannelHost::~GpuChannelHost() {
// channel_ must be destroyed on the main thread.
if (!factory_->IsMainThread())
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index 5efa98d..87240ef 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -24,6 +24,7 @@
#include "ipc/ipc_sync_channel.h"
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
+#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gl/gpu_preference.h"
@@ -77,6 +78,10 @@ class CONTENT_EXPORT GpuChannelHostFactory {
int32 image_id,
const CreateImageCallback& callback) = 0;
virtual void DeleteImage(int32 image_id, int32 sync_point) = 0;
+ virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+ size_t width,
+ size_t height,
+ unsigned internalformat) = 0;
};
// Encapsulates an IPC channel between the client and one GPU process.
@@ -94,6 +99,10 @@ class GpuChannelHost : public IPC::Sender,
const gpu::GPUInfo& gpu_info,
const IPC::ChannelHandle& channel_handle);
+ // Returns true if |handle| is a valid GpuMemoryBuffer handle that
+ // can be shared to the GPU process.
+ static bool IsValidGpuMemoryBuffer(gfx::GpuMemoryBufferHandle handle);
+
bool IsLost() const {
DCHECK(channel_filter_.get());
return channel_filter_->IsLost();
@@ -162,6 +171,15 @@ class GpuChannelHost : public IPC::Sender,
// Reserve one unused transfer buffer ID.
int32 ReserveTransferBufferId();
+ // Returns a GPU memory buffer handle to the buffer that can be sent via
+ // IPC to the GPU process. The caller is responsible for ensuring it is
+ // closed. Returns an invalid handle on failure.
+ gfx::GpuMemoryBufferHandle ShareGpuMemoryBufferToGpuProcess(
+ gfx::GpuMemoryBufferHandle source_handle);
+
+ // Reserve one unused gpu memory buffer ID.
+ int32 ReserveGpuMemoryBufferId();
+
private:
friend class base::RefCountedThreadSafe<GpuChannelHost>;
GpuChannelHost(GpuChannelHostFactory* factory,
@@ -228,6 +246,7 @@ class GpuChannelHost : public IPC::Sender,
// Threading notes: all fields are constant during the lifetime of |this|
// except:
// - |next_transfer_buffer_id_|, atomic type
+ // - |next_gpu_memory_buffer_id_|, atomic type
// - |proxies_|, protected by |context_lock_|
GpuChannelHostFactory* const factory_;
const int client_id_;
@@ -244,6 +263,9 @@ class GpuChannelHost : public IPC::Sender,
// Transfer buffer IDs are allocated in sequence.
base::AtomicSequenceNumber next_transfer_buffer_id_;
+ // Gpu memory buffer IDs are allocated in sequence.
+ base::AtomicSequenceNumber next_gpu_memory_buffer_id_;
+
// Protects proxies_.
mutable base::Lock context_lock_;
// Used to look up a proxy from its routing id.
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.cc b/content/common/gpu/client/gpu_memory_buffer_impl.cc
new file mode 100644
index 0000000..e5f6bc5
--- /dev/null
+++ b/content/common/gpu/client/gpu_memory_buffer_impl.cc
@@ -0,0 +1,80 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
+
+#include "ui/gl/gl_bindings.h"
+
+namespace content {
+
+GpuMemoryBufferImpl::GpuMemoryBufferImpl(
+ scoped_ptr<base::SharedMemory> shared_memory,
+ size_t width,
+ size_t height,
+ unsigned internalformat)
+ : shared_memory_(shared_memory.Pass()),
+ size_(gfx::Size(width, height)),
+ internalformat_(internalformat),
+ mapped_(false) {
+ DCHECK(!shared_memory_->memory());
+ DCHECK(IsFormatValid(internalformat));
+}
+
+GpuMemoryBufferImpl::~GpuMemoryBufferImpl() {
+}
+
+void GpuMemoryBufferImpl::Map(AccessMode mode, void** vaddr) {
+ DCHECK(!mapped_);
+ *vaddr = NULL;
+ if (!shared_memory_->Map(size_.GetArea() * BytesPerPixel(internalformat_)))
+ return;
+ *vaddr = shared_memory_->memory();
+ mapped_ = true;
+}
+
+void GpuMemoryBufferImpl::Unmap() {
+ DCHECK(mapped_);
+ shared_memory_->Unmap();
+ mapped_ = false;
+}
+
+bool GpuMemoryBufferImpl::IsMapped() const {
+ return mapped_;
+}
+
+uint32 GpuMemoryBufferImpl::GetStride() const {
+ return size_.width() * BytesPerPixel(internalformat_);
+}
+
+gfx::GpuMemoryBufferHandle GpuMemoryBufferImpl::GetHandle() const {
+ gfx::GpuMemoryBufferHandle handle;
+ handle.type = gfx::SHARED_MEMORY_BUFFER;
+ handle.handle = shared_memory_->handle();
+ return handle;
+}
+
+// static
+bool GpuMemoryBufferImpl::IsFormatValid(unsigned internalformat) {
+ // GL_RGBA8_OES is the only supported format at the moment.
+ switch (internalformat) {
+ case GL_RGBA8_OES:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// static
+size_t GpuMemoryBufferImpl::BytesPerPixel(unsigned internalformat) {
+ // GL_RGBA_OES has 4 bytes per pixel.
+ switch (internalformat) {
+ case GL_RGBA8_OES:
+ return 4;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+} // namespace content
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.h b/content/common/gpu/client/gpu_memory_buffer_impl.h
new file mode 100644
index 0000000..3858c3f
--- /dev/null
+++ b/content/common/gpu/client/gpu_memory_buffer_impl.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_
+#define CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gfx/size.h"
+
+namespace content {
+
+// Provides common implementation of a GPU memory buffer based
+// on a shared memory handle.
+class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
+ public:
+ GpuMemoryBufferImpl(scoped_ptr<base::SharedMemory> shared_memory,
+ size_t width,
+ size_t height,
+ unsigned internalformat);
+ virtual ~GpuMemoryBufferImpl();
+
+ // Overridden from gfx::GpuMemoryBuffer:
+ virtual void Map(AccessMode mode, void** vaddr) OVERRIDE;
+ virtual void Unmap() OVERRIDE;
+ virtual bool IsMapped() const OVERRIDE;
+ virtual uint32 GetStride() const OVERRIDE;
+ virtual gfx::GpuMemoryBufferHandle GetHandle() const OVERRIDE;
+
+ static bool IsFormatValid(unsigned internalformat);
+ static size_t BytesPerPixel(unsigned internalformat);
+
+ private:
+ scoped_ptr<base::SharedMemory> shared_memory_;
+ const gfx::Size size_;
+ unsigned internalformat_;
+ bool mapped_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_CLIENT_GPU_MEMORY_BUFFER_IMPL_H_
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
index bd4ebab..ccbde6f 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -147,6 +147,11 @@ void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3) { \
gl_->glname(a1, a2, a3); \
}
+#define DELEGATE_TO_GL_3R(name, glname, t1, t2, t3, rt) \
+rt WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3) { \
+ return gl_->glname(a1, a2, a3); \
+}
+
#define DELEGATE_TO_GL_4(name, glname, t1, t2, t3, t4) \
void WebGraphicsContext3DCommandBufferImpl::name(t1 a1, t2 a2, t3 a3, \
t4 a4) { \
@@ -1525,6 +1530,20 @@ void WebGraphicsContext3DCommandBufferImpl::drawElementsInstancedANGLE(
DELEGATE_TO_GL_2(vertexAttribDivisorANGLE, VertexAttribDivisorANGLE, WGC3Duint,
WGC3Duint)
+DELEGATE_TO_GL_3R(createImageCHROMIUM, CreateImageCHROMIUM,
+ WGC3Dsizei, WGC3Dsizei, WGC3Denum,
+ WGC3Duint);
+
+DELEGATE_TO_GL_1(destroyImageCHROMIUM, DestroyImageCHROMIUM, WGC3Duint);
+
+DELEGATE_TO_GL_3(getImageParameterivCHROMIUM, GetImageParameterivCHROMIUM,
+ WGC3Duint, WGC3Denum, GLint*);
+
+DELEGATE_TO_GL_2R(mapImageCHROMIUM, MapImageCHROMIUM,
+ WGC3Duint, WGC3Denum, void*);
+
+DELEGATE_TO_GL_1(unmapImageCHROMIUM, UnmapImageCHROMIUM, WGC3Duint);
+
GrGLInterface* WebGraphicsContext3DCommandBufferImpl::createGrGLInterface() {
return webkit::gpu::CreateCommandBufferSkiaGLBinding();
}
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
index 7a03d33..59eb665 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
@@ -640,6 +640,15 @@ class WebGraphicsContext3DCommandBufferImpl
WGC3Denum type, WGC3Dintptr offset, WGC3Dsizei primcount);
virtual void vertexAttribDivisorANGLE(WGC3Duint index, WGC3Duint divisor);
+ // GL_CHROMIUM_map_image
+ virtual WGC3Duint createImageCHROMIUM(
+ WGC3Dsizei width, WGC3Dsizei height, WGC3Denum internalformat);
+ virtual void destroyImageCHROMIUM(WGC3Duint image_id);
+ virtual void getImageParameterivCHROMIUM(
+ WGC3Duint image_id, WGC3Denum pname, WGC3Dint* params);
+ virtual void* mapImageCHROMIUM(WGC3Duint image_id, WGC3Denum access);
+ virtual void unmapImageCHROMIUM(WGC3Duint image_id);
+
virtual GrGLInterface* createGrGLInterface();
private:
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index 05792bf..9030ffe 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -26,6 +26,8 @@
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/service/gl_context_virtual.h"
#include "gpu/command_buffer/service/gl_state_restorer_impl.h"
+#include "gpu/command_buffer/service/gpu_control_service.h"
+#include "gpu/command_buffer/service/image_manager.h"
#include "gpu/command_buffer/service/logger.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/command_buffer/service/query_manager.h"
@@ -223,6 +225,10 @@ bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(
GpuCommandBufferMsg_SetClientHasMemoryAllocationChangedCallback,
OnSetClientHasMemoryAllocationChangedCallback)
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RegisterGpuMemoryBuffer,
+ OnRegisterGpuMemoryBuffer);
+ IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyGpuMemoryBuffer,
+ OnDestroyGpuMemoryBuffer);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -403,6 +409,12 @@ void GpuCommandBufferStub::OnInitialize(
return;
}
+ gpu_control_.reset(
+ new gpu::GpuControlService(context_group_->image_manager(),
+ NULL,
+ context_group_->mailbox_manager(),
+ NULL));
+
decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group_.get()));
scheduler_.reset(new gpu::GpuScheduler(command_buffer_.get(),
@@ -848,6 +860,28 @@ void GpuCommandBufferStub::OnSetClientHasMemoryAllocationChangedCallback(
}
}
+void GpuCommandBufferStub::OnRegisterGpuMemoryBuffer(
+ int32 id,
+ gfx::GpuMemoryBufferHandle gpu_memory_buffer,
+ uint32 width,
+ uint32 height,
+ uint32 internalformat) {
+ TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnRegisterGpuMemoryBuffer");
+ if (gpu_control_) {
+ gpu_control_->RegisterGpuMemoryBuffer(id,
+ gpu_memory_buffer,
+ width,
+ height,
+ internalformat);
+ }
+}
+
+void GpuCommandBufferStub::OnDestroyGpuMemoryBuffer(int32 id) {
+ TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDestroyGpuMemoryBuffer");
+ if (gpu_control_)
+ gpu_control_->DestroyGpuMemoryBuffer(id);
+}
+
void GpuCommandBufferStub::SendConsoleMessage(
int32 id,
const std::string& message) {
diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h
index 47c532b..a5258f2 100644
--- a/content/common/gpu/gpu_command_buffer_stub.h
+++ b/content/common/gpu/gpu_command_buffer_stub.h
@@ -24,6 +24,7 @@
#include "ipc/ipc_sender.h"
#include "media/base/video_decoder_config.h"
#include "ui/events/latency_info.h"
+#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gl/gl_surface.h"
@@ -31,6 +32,7 @@
#include "url/gurl.h"
namespace gpu {
+class GpuControlService;
struct Mailbox;
namespace gles2 {
class ImageManager;
@@ -181,6 +183,13 @@ class GpuCommandBufferStub
void OnReceivedClientManagedMemoryStats(const GpuManagedMemoryStats& stats);
void OnSetClientHasMemoryAllocationChangedCallback(bool has_callback);
+ void OnRegisterGpuMemoryBuffer(int32 id,
+ gfx::GpuMemoryBufferHandle gpu_memory_buffer,
+ uint32 width,
+ uint32 height,
+ uint32 internalformat);
+ void OnDestroyGpuMemoryBuffer(int32 id);
+
void OnCommandProcessed();
void OnParseError();
void OnSetLatencyInfo(const ui::LatencyInfo& latency_info);
@@ -223,6 +232,7 @@ class GpuCommandBufferStub
scoped_ptr<gpu::gles2::GLES2Decoder> decoder_;
scoped_ptr<gpu::GpuScheduler> scheduler_;
scoped_refptr<gfx::GLSurface> surface_;
+ scoped_ptr<gpu::GpuControlService> gpu_control_;
scoped_ptr<GpuMemoryManagerClientState> memory_manager_client_state_;
// The last memory allocation received from the GpuMemoryManager (used to
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 124815b..3c2bb28 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -27,6 +27,7 @@
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/events/latency_info.h"
+#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gl/gpu_preference.h"
@@ -548,7 +549,7 @@ IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_Rescheduled)
IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_ConsoleMsg,
GPUCommandBufferConsoleMessage /* msg */)
-// Register an existing shared memory transfer buffer. Returns an id that can be
+// Register an existing shared memory transfer buffer. The id that can be
// used to identify the transfer buffer from a command buffer.
IPC_MESSAGE_ROUTED3(GpuCommandBufferMsg_RegisterTransferBuffer,
int32 /* id */,
@@ -637,6 +638,19 @@ IPC_MESSAGE_ROUTED2(GpuCommandBufferMsg_SignalQuery,
uint32 /* query */,
uint32 /* signal_id */)
+// Register an existing gpu memory buffer. The id that can be
+// used to identify the gpu memory buffer from a command buffer.
+IPC_MESSAGE_ROUTED5(GpuCommandBufferMsg_RegisterGpuMemoryBuffer,
+ int32 /* id */,
+ gfx::GpuMemoryBufferHandle /* gpu_memory_buffer */,
+ uint32 /* width */,
+ uint32 /* height */,
+ uint32 /* internalformat */)
+
+// Destroy a previously created gpu memory buffer.
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_DestroyGpuMemoryBuffer,
+ int32 /* id */)
+
//------------------------------------------------------------------------------
// Accelerated Video Decoder Messages
// These messages are sent from Renderer process to GPU process.
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 18edca34..ef8293d 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -190,6 +190,8 @@
'common/gpu/client/gl_helper_scaling.h',
'common/gpu/client/gpu_channel_host.cc',
'common/gpu/client/gpu_channel_host.h',
+ 'common/gpu/client/gpu_memory_buffer_impl.cc',
+ 'common/gpu/client/gpu_memory_buffer_impl.h',
'common/gpu/client/gpu_video_decode_accelerator_host.cc',
'common/gpu/client/gpu_video_decode_accelerator_host.h',
'common/gpu/client/gpu_video_encode_accelerator_host.cc',
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 4f719e3..aa5b565 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -44,6 +44,7 @@
#include "content/common/dom_storage/dom_storage_messages.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/resource_messages.h"
#include "content/common/view_messages.h"
@@ -1052,6 +1053,47 @@ void RenderThreadImpl::DeleteImage(int32 image_id, int32 sync_point) {
NOTREACHED();
}
+scoped_ptr<gfx::GpuMemoryBuffer> RenderThreadImpl::AllocateGpuMemoryBuffer(
+ size_t width,
+ size_t height,
+ unsigned internalformat) {
+ if (!GpuMemoryBufferImpl::IsFormatValid(internalformat))
+ return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+ size_t size = width * height *
+ GpuMemoryBufferImpl::BytesPerPixel(internalformat);
+ if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+ return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+ gfx::GpuMemoryBufferHandle handle;
+ bool success;
+ IPC::Message* message =
+ new ChildProcessHostMsg_SyncAllocateGpuMemoryBuffer(size, &handle);
+
+ // Allow calling this from the compositor thread.
+ if (base::MessageLoop::current() == message_loop())
+ success = ChildThread::Send(message);
+ else
+ success = sync_message_filter()->Send(message);
+
+ if (!success)
+ return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+ // Currently, shared memory is the only supported buffer type.
+ if (handle.type != gfx::SHARED_MEMORY_BUFFER)
+ return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+ if (!base::SharedMemory::IsHandleValid(handle.handle))
+ return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+ return make_scoped_ptr<gfx::GpuMemoryBuffer>(
+ new GpuMemoryBufferImpl(
+ make_scoped_ptr(new base::SharedMemory(handle.handle, false)),
+ width,
+ height,
+ internalformat));
+}
+
void RenderThreadImpl::DoNotSuspendWebKitSharedTimer() {
suspend_webkit_shared_timer_ = false;
}
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index b2e7e9b..e1f4ec9 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -364,6 +364,10 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
int32 image_id,
const CreateImageCallback& callback) OVERRIDE;
virtual void DeleteImage(int32 image_id, int32 sync_point) OVERRIDE;
+ virtual scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBuffer(
+ size_t width,
+ size_t height,
+ unsigned internalformat) OVERRIDE;
void Init();