Remove renderer dependencies from the GPU client classes.

A future CL will move them out of content/renderer so that they can be used by
the browser process.
All requests to singleton-like things - e.g. establish a channel to the GPU
process - go through a GpuChannelHostFactory, implemented by RenderThreadImpl.

BUG=99516
TEST=manually tested Chrome with accelerated content.


Review URL: http://codereview.chromium.org/9270025

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@120701 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/content/renderer/gpu/command_buffer_proxy.cc b/content/renderer/gpu/command_buffer_proxy.cc
index 384e6e2..82c0676 100644
--- a/content/renderer/gpu/command_buffer_proxy.cc
+++ b/content/renderer/gpu/command_buffer_proxy.cc
@@ -101,8 +101,7 @@
 }
 
 bool CommandBufferProxy::Initialize() {
-  ChildThread* child_thread = ChildThread::current();
-  if (!child_thread)
+  if (!channel_->factory()->IsMainThread())
     return false;
 
   bool result;
@@ -179,30 +178,18 @@
   if (last_state_.error != gpu::error::kNoError)
     return -1;
 
-  ChildThread* child_thread = ChildThread::current();
-  if (!child_thread)
-    return -1;
-
-  base::SharedMemoryHandle handle;
-  if (!child_thread->Send(new ChildProcessHostMsg_SyncAllocateSharedMemory(
-      size,
-      &handle))) {
-    return -1;
-  }
-
-  if (!base::SharedMemory::IsHandleValid(handle))
-    return -1;
-
-  // Handle is closed by the SharedMemory object below. This stops
-  // base::FileDescriptor from closing it as well.
-#if defined(OS_POSIX)
-  handle.auto_close = false;
-#endif
-
   // Take ownership of shared memory. This will close the handle if Send below
   // fails. Otherwise, callee takes ownership before this variable
   // goes out of scope by duping the handle.
-  base::SharedMemory shared_memory(handle, false);
+  scoped_ptr<base::SharedMemory> shm(
+      channel_->factory()->AllocateSharedMemory(size));
+  if (!shm.get())
+    return -1;
+
+  base::SharedMemoryHandle handle = shm->handle();
+#if defined(OS_POSIX)
+  DCHECK(!handle.auto_close);
+#endif
 
   int32 id;
   if (!Send(new GpuCommandBufferMsg_RegisterTransferBuffer(route_id_,
diff --git a/content/renderer/gpu/gpu_channel_host.cc b/content/renderer/gpu/gpu_channel_host.cc
index 96c652b..05d73d5 100644
--- a/content/renderer/gpu/gpu_channel_host.cc
+++ b/content/renderer/gpu/gpu_channel_host.cc
@@ -7,14 +7,18 @@
 #include "base/bind.h"
 #include "base/message_loop.h"
 #include "base/message_loop_proxy.h"
-#include "content/common/child_process.h"
+#include "content/common/child_thread.h"
 #include "content/common/gpu/gpu_messages.h"
 #include "content/renderer/gpu/command_buffer_proxy.h"
-#include "content/renderer/render_process.h"
-#include "content/renderer/render_thread_impl.h"
 #include "googleurl/src/gurl.h"
 #include "ipc/ipc_sync_message_filter.h"
 
+GpuChannelHostFactory* GpuChannelHostFactory::instance_ = NULL;
+
+GpuChannelHostFactory::~GpuChannelHostFactory() {
+  DCHECK(!instance_);
+}
+
 using base::AutoLock;
 using base::MessageLoopProxy;
 
@@ -36,7 +40,7 @@
     int route_id,
     base::WeakPtr<IPC::Channel::Listener> listener,
     scoped_refptr<MessageLoopProxy> loop) {
-  DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
+  DCHECK(parent_->factory_->IsIOThread());
   DCHECK(listeners_.find(route_id) == listeners_.end());
   GpuListenerInfo info;
   info.listener = listener;
@@ -45,7 +49,7 @@
 }
 
 void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) {
-  DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
+  DCHECK(parent_->factory_->IsIOThread());
   ListenerMap::iterator it = listeners_.find(route_id);
   if (it != listeners_.end())
     listeners_.erase(it);
@@ -53,7 +57,7 @@
 
 bool GpuChannelHost::MessageFilter::OnMessageReceived(
     const IPC::Message& message) {
-  DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
+  DCHECK(parent_->factory_->IsIOThread());
   // Never handle sync message replies or we will deadlock here.
   if (message.is_reply())
     return false;
@@ -76,7 +80,7 @@
 }
 
 void GpuChannelHost::MessageFilter::OnChannelError() {
-  DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
+  DCHECK(parent_->factory_->IsIOThread());
   // Inform all the proxies that an error has occurred. This will be reported
   // via OpenGL as a lost context.
   for (ListenerMap::iterator it = listeners_.begin();
@@ -90,14 +94,14 @@
 
   listeners_.clear();
 
-  ChildThread* main_thread = RenderProcess::current()->main_thread();
-  MessageLoop* main_loop = main_thread->message_loop();
+  MessageLoop* main_loop = parent_->factory_->GetMainLoop();
   main_loop->PostTask(FROM_HERE,
                       base::Bind(&GpuChannelHost::OnChannelError, parent_));
 }
 
-GpuChannelHost::GpuChannelHost()
-    : state_(kUnconnected) {
+GpuChannelHost::GpuChannelHost(GpuChannelHostFactory* factory)
+    : factory_(factory),
+      state_(kUnconnected) {
 }
 
 GpuChannelHost::~GpuChannelHost() {
@@ -106,16 +110,16 @@
 void GpuChannelHost::Connect(
     const IPC::ChannelHandle& channel_handle,
     base::ProcessHandle renderer_process_for_gpu) {
-  DCHECK(RenderThreadImpl::current());
+  DCHECK(factory_->IsMainThread());
   // Open a channel to the GPU process. We pass NULL as the main listener here
   // since we need to filter everything to route it to the right thread.
   channel_.reset(new IPC::SyncChannel(
       channel_handle, IPC::Channel::MODE_CLIENT, NULL,
-      ChildProcess::current()->io_message_loop_proxy(), true,
-      ChildProcess::current()->GetShutDownEvent()));
+      factory_->GetIOLoopProxy(), true,
+      factory_->GetShutDownEvent()));
 
   sync_filter_ = new IPC::SyncMessageFilter(
-      ChildProcess::current()->GetShutDownEvent());
+      factory_->GetShutDownEvent());
 
   channel_->AddFilter(sync_filter_.get());
 
@@ -163,12 +167,12 @@
   // Currently we need to choose between two different mechanisms for sending.
   // On the main thread we use the regular channel Send() method, on another
   // thread we use SyncMessageFilter. We also have to be careful interpreting
-  // RenderThreadImpl::current() since it might return NULL during shutdown,
+  // IsMainThread() since it might return false during shutdown,
   // impl we are actually calling from the main thread (discard message then).
   //
   // TODO: Can we just always use sync_filter_ since we setup the channel
   //       without a main listener?
-  if (RenderThreadImpl::current()) {
+  if (factory_->IsMainThread()) {
     if (channel_.get())
       return channel_->Send(message);
   } else if (MessageLoop::current()) {
@@ -188,7 +192,7 @@
     const std::vector<int32>& attribs,
     const GURL& active_url,
     gfx::GpuPreference gpu_preference) {
-  DCHECK(ChildThread::current());
+  DCHECK(factory_->IsMainThread());
 #if defined(ENABLE_GPU)
   AutoLock lock(context_lock_);
   // An error occurred. Need to get the host again to reinitialize it.
@@ -202,15 +206,7 @@
   init_params.attribs = attribs;
   init_params.active_url = active_url;
   init_params.gpu_preference = gpu_preference;
-  int32 route_id;
-  if (!ChildThread::current()->Send(
-      new GpuHostMsg_CreateViewCommandBuffer(
-          surface_id,
-          init_params,
-          &route_id))) {
-    return NULL;
-  }
-
+  int32 route_id = factory_->CreateViewCommandBuffer(surface_id, init_params);
   if (route_id == MSG_ROUTING_NONE)
     return NULL;
 
@@ -291,7 +287,7 @@
     int route_id, base::WeakPtr<IPC::Channel::Listener> listener) {
   DCHECK(MessageLoopProxy::current());
 
-  MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy();
+  MessageLoopProxy* io_loop = factory_->GetIOLoopProxy();
   io_loop->PostTask(FROM_HERE,
                     base::Bind(&GpuChannelHost::MessageFilter::AddRoute,
                                channel_filter_.get(), route_id, listener,
@@ -299,7 +295,7 @@
 }
 
 void GpuChannelHost::RemoveRoute(int route_id) {
-  MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy();
+  MessageLoopProxy* io_loop = factory_->GetIOLoopProxy();
   io_loop->PostTask(FROM_HERE,
                     base::Bind(&GpuChannelHost::MessageFilter::RemoveRoute,
                                channel_filter_.get(), route_id));
diff --git a/content/renderer/gpu/gpu_channel_host.h b/content/renderer/gpu/gpu_channel_host.h
index 554fe19..f06f1c90 100644
--- a/content/renderer/gpu/gpu_channel_host.h
+++ b/content/renderer/gpu/gpu_channel_host.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/process_util.h"
 #include "base/synchronization/lock.h"
+#include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/common/message_router.h"
 #include "content/public/common/gpu_info.h"
 #include "content/renderer/gpu/gpu_video_decode_accelerator_host.h"
@@ -26,8 +27,10 @@
 #include "ui/gfx/size.h"
 
 class CommandBufferProxy;
+struct GPUCreateCommandBufferConfig;
 class GURL;
 class TransportTextureService;
+class MessageLoop;
 
 namespace base {
 class MessageLoopProxy;
@@ -45,6 +48,31 @@
   scoped_refptr<base::MessageLoopProxy> loop;
 };
 
+class GpuChannelHostFactory {
+ public:
+  virtual ~GpuChannelHostFactory();
+  static GpuChannelHostFactory* instance() { return instance_; }
+
+  virtual bool IsMainThread() = 0;
+  virtual bool IsIOThread() = 0;
+  virtual MessageLoop* GetMainLoop() = 0;
+  virtual base::MessageLoopProxy* GetIOLoopProxy() = 0;
+  virtual base::WaitableEvent* GetShutDownEvent() = 0;
+  virtual scoped_ptr<base::SharedMemory> AllocateSharedMemory(uint32 size) = 0;
+  virtual int32 CreateViewCommandBuffer(
+      int32 surface_id, const GPUCreateCommandBufferConfig& init_params) = 0;
+  virtual GpuChannelHost* EstablishGpuChannelSync(
+      content::CauseForGpuLaunch) = 0;
+
+ protected:
+  static void set_instance(GpuChannelHostFactory* instance) {
+    instance_ = instance;
+  }
+
+ private:
+  static GpuChannelHostFactory* instance_;
+};
+
 // Encapsulates an IPC channel between the renderer and one plugin process.
 // On the plugin side there's a corresponding GpuChannel.
 class GpuChannelHost : public IPC::Message::Sender,
@@ -61,7 +89,7 @@
   };
 
   // Called on the render thread
-  GpuChannelHost();
+  explicit GpuChannelHost(GpuChannelHostFactory* factory);
   virtual ~GpuChannelHost();
 
   // Connect to GPU process channel.
@@ -128,6 +156,8 @@
   // the state on this side to lost.
   void ForciblyCloseChannel();
 
+  GpuChannelHostFactory* factory() const { return factory_; }
+
  private:
   // A filter used internally to route incoming messages from the IO thread
   // to the correct message loop.
@@ -152,6 +182,8 @@
     ListenerMap listeners_;
   };
 
+  GpuChannelHostFactory* factory_;
+
   State state_;
 
   content::GPUInfo gpu_info_;
diff --git a/content/renderer/gpu/gpu_video_decode_accelerator_host.cc b/content/renderer/gpu/gpu_video_decode_accelerator_host.cc
index da294f1..de9e1d641 100644
--- a/content/renderer/gpu/gpu_video_decode_accelerator_host.cc
+++ b/content/renderer/gpu/gpu_video_decode_accelerator_host.cc
@@ -10,7 +10,6 @@
 #include "content/common/gpu/gpu_messages.h"
 #include "content/common/view_messages.h"
 #include "content/renderer/gpu/gpu_channel_host.h"
-#include "content/renderer/render_thread_impl.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_message_utils.h"
 
diff --git a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc
index cf65d36..99f839d 100644
--- a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if defined(ENABLE_GPU)
-
 #include "content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h"
 
 #include "third_party/khronos/GLES2/gl2.h"
@@ -24,17 +22,12 @@
 #include "base/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/synchronization/lock.h"
-#include "content/common/child_process.h"
 #include "content/public/common/content_switches.h"
 #include "content/renderer/gpu/command_buffer_proxy.h"
 #include "content/renderer/gpu/gpu_channel_host.h"
-#include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
 #include "gpu/command_buffer/common/constants.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
 #include "webkit/glue/gl_bindings_skia_cmd_buffer.h"
 
 static base::LazyInstance<base::Lock>::Leaky
@@ -52,14 +45,17 @@
 } // namespace anonymous
 
 
-WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl()
+WebGraphicsContext3DCommandBufferImpl::WebGraphicsContext3DCommandBufferImpl(
+    int surface_id,
+    const GURL& active_url,
+    const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client)
     : initialize_failed_(false),
       context_(NULL),
       gl_(NULL),
-      web_view_(NULL),
-#if defined(OS_MACOSX)
-      plugin_handle_(NULL),
-#endif  // defined(OS_MACOSX)
+      host_(NULL),
+      surface_id_(surface_id),
+      active_url_(active_url),
+      swap_client_(swap_client),
       context_lost_callback_(0),
       context_lost_reason_(GL_NO_ERROR),
       swapbuffers_complete_callback_(0),
@@ -86,14 +82,12 @@
   delete context_;
 }
 
-bool WebGraphicsContext3DCommandBufferImpl::initialize(
-    WebGraphicsContext3D::Attributes attributes,
-    WebKit::WebView* web_view,
-    bool render_directly_to_web_view) {
+bool WebGraphicsContext3DCommandBufferImpl::Initialize(
+    const WebGraphicsContext3D::Attributes& attributes) {
   DCHECK(!context_);
   TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::initialize");
-  RenderThreadImpl* render_thread = RenderThreadImpl::current();
-  if (!render_thread)
+  GpuChannelHostFactory* factory = GpuChannelHostFactory::instance();
+  if (!factory)
     return false;
 
   // The noExtensions and canRecoverFromContextLoss flags are
@@ -106,7 +100,7 @@
 
   // Note similar code in Pepper PlatformContext3DImpl::Init.
   do {
-    host_ = render_thread->EstablishGpuChannelSync(
+    host_ = factory->EstablishGpuChannelSync(
         content::
         CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE);
     if (!host_)
@@ -137,18 +131,7 @@
       return false;
   }
 
-  if (web_view && web_view->mainFrame())
-    active_url_ = GURL(web_view->mainFrame()->document().url());
-
   attributes_ = attributes;
-  render_directly_to_web_view_ = render_directly_to_web_view;
-  if (render_directly_to_web_view_) {
-    RenderViewImpl* render_view = RenderViewImpl::FromWebView(web_view);
-    if (!render_view)
-      return false;
-    surface_id_ = render_view->surface_id();
-    web_view_ = web_view;
-  }
   return true;
 }
 
@@ -161,12 +144,11 @@
   TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::MaybeInitializeGL");
 
   // If the context is being initialized on something other than the main
-  // thread, then drop the web_view_ pointer so we don't accidentally
-  // dereference it.
-  MessageLoop* main_message_loop =
-      ChildProcess::current()->main_thread()->message_loop();
-  if (MessageLoop::current() != main_message_loop)
-    web_view_ = NULL;
+  // thread, then make sure the swap_client_ pointer is NULL so we don't
+  // accidentally dereference it.
+  GpuChannelHostFactory* factory = GpuChannelHostFactory::instance();
+  if (!factory || !factory->IsMainThread())
+    DCHECK(!swap_client_.get());
 
   // Convert WebGL context creation attributes into RendererGLContext / EGL size
   // requests.
@@ -199,7 +181,7 @@
           NULL : (*g_all_shared_contexts.Pointer()->begin())->context_;
     }
 
-    if (render_directly_to_web_view_) {
+    if (surface_id_) {
       context_ = RendererGLContext::CreateViewContext(
           host_,
           surface_id_,
@@ -297,10 +279,8 @@
 void WebGraphicsContext3DCommandBufferImpl::prepareTexture() {
   // Copies the contents of the off-screen render target into the texture
   // used by the compositor.
-  RenderViewImpl* renderview =
-      web_view_ ? RenderViewImpl::FromWebView(web_view_) : NULL;
-  if (renderview)
-    renderview->OnViewContextSwapBuffersPosted();
+  if (swap_client_.get())
+    swap_client_->OnViewContextSwapBuffersPosted();
   context_->SwapBuffers();
   context_->Echo(base::Bind(
       &WebGraphicsContext3DCommandBufferImpl::OnSwapBuffersComplete,
@@ -317,10 +297,8 @@
     int x, int y, int width, int height) {
   // Same flow control as WebGraphicsContext3DCommandBufferImpl::prepareTexture
   // (see above).
-  RenderViewImpl* renderview =
-      web_view_ ? RenderViewImpl::FromWebView(web_view_) : NULL;
-  if (renderview)
-    renderview->OnViewContextSwapBuffersPosted();
+  if (swap_client_.get())
+    swap_client_->OnViewContextSwapBuffersPosted();
   gl_->PostSubBufferCHROMIUM(x, y, width, height);
   context_->Echo(base::Bind(
       &WebGraphicsContext3DCommandBufferImpl::OnSwapBuffersComplete,
@@ -1131,14 +1109,11 @@
 }
 
 void WebGraphicsContext3DCommandBufferImpl::OnSwapBuffersComplete() {
+  typedef WebGraphicsContext3DSwapBuffersClient WGC3DSwapClient;
   // This may be called after tear-down of the RenderView.
-  RenderViewImpl* renderview =
-      web_view_ ? RenderViewImpl::FromWebView(web_view_) : NULL;
-  if (renderview) {
-    MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&RenderViewImpl::OnViewContextSwapBuffersComplete,
-                   renderview));
+  if (swap_client_.get()) {
+    MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+        &WGC3DSwapClient::OnViewContextSwapBuffersComplete, swap_client_));
   }
 
   if (swapbuffers_complete_callback_)
@@ -1203,10 +1178,6 @@
   }
   if (attributes_.shareResources)
     ClearSharedContexts();
-  RenderViewImpl* renderview =
-      web_view_ ? RenderViewImpl::FromWebView(web_view_) : NULL;
-  if (renderview)
-    renderview->OnViewContextSwapBuffersAborted();
+  if (swap_client_.get())
+    swap_client_->OnViewContextSwapBuffersAborted();
 }
-
-#endif  // defined(ENABLE_GPU)
diff --git a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h
index 0137b38..778c2ce 100644
--- a/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h
+++ b/content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h
@@ -6,8 +6,6 @@
 #define CONTENT_RENDERER_GPU_WEBGRAPHICSCONTEXT3D_COMMAND_BUFFER_IMPL_H_
 #pragma once
 
-#if defined(ENABLE_GPU)
-
 #include <string>
 #include <vector>
 
@@ -47,17 +45,29 @@
 using WebKit::WGC3Dintptr;
 using WebKit::WGC3Dsizeiptr;
 
+// TODO(piman): move this logic to the compositor and remove it from the
+// context...
+class WebGraphicsContext3DSwapBuffersClient {
+ public:
+  virtual ~WebGraphicsContext3DSwapBuffersClient() { }
+  virtual void OnViewContextSwapBuffersPosted() = 0;
+  virtual void OnViewContextSwapBuffersComplete() = 0;
+  virtual void OnViewContextSwapBuffersAborted() = 0;
+};
+
 class WebGraphicsContext3DCommandBufferImpl
     : public WebKit::WebGraphicsContext3D {
  public:
-  WebGraphicsContext3DCommandBufferImpl();
+  WebGraphicsContext3DCommandBufferImpl(
+      int surface_id,
+      const GURL& active_url,
+      const base::WeakPtr<WebGraphicsContext3DSwapBuffersClient>& swap_client);
   virtual ~WebGraphicsContext3DCommandBufferImpl();
 
+  bool Initialize(const Attributes& attributes);
+
   //----------------------------------------------------------------------
   // WebGraphicsContext3D methods
-  virtual bool initialize(WebGraphicsContext3D::Attributes attributes,
-                          WebKit::WebView*,
-                          bool renderDirectlyToWebView);
 
   // Must be called after initialize() and before any of the following methods.
   // Permanently binds to the first calling thread. Returns false if the
@@ -490,19 +500,10 @@
 
   // State needed by MaybeInitializeGL.
   GpuChannelHost* host_;
-  GURL active_url_;
   int32 surface_id_;
+  GURL active_url_;
+  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client_;
 
-  bool render_directly_to_web_view_;
-
-  // If rendering directly to WebView, weak pointer to it.
-  // This is only set when the context is bound to the main thread.
-  WebKit::WebView* web_view_;
-
-#if defined(OS_MACOSX)
-  // "Fake" plugin window handle in browser process for the compositor's output.
-  gfx::PluginWindowHandle plugin_handle_;
-#endif
   WebGraphicsContext3D::WebGraphicsContextLostCallback* context_lost_callback_;
   WGC3Denum context_lost_reason_;
 
@@ -529,5 +530,4 @@
 #endif
 };
 
-#endif  // defined(ENABLE_GPU)
 #endif  // CONTENT_RENDERER_GPU_WEBGRAPHICSCONTEXT3D_COMMAND_BUFFER_IMPL_H_
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 578d6aaf..064f080 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -180,6 +180,8 @@
 #endif
 
   lazy_tls.Pointer()->Set(this);
+  GpuChannelHostFactory::set_instance(this);
+
 #if defined(OS_WIN)
   // If you are running plugins in this thread you need COM active but in
   // the normal case you don't.
@@ -267,6 +269,7 @@
   if (webkit_platform_support_.get())
     WebKit::shutdown();
 
+  GpuChannelHostFactory::set_instance(NULL);
   lazy_tls.Pointer()->Set(NULL);
 
   // TODO(port)
@@ -677,6 +680,50 @@
 
 #endif  // OS_WIN
 
+bool RenderThreadImpl::IsMainThread() {
+  return !!current();
+}
+
+bool RenderThreadImpl::IsIOThread() {
+  return MessageLoop::current() == ChildProcess::current()->io_message_loop();
+}
+
+MessageLoop* RenderThreadImpl::GetMainLoop() {
+  return message_loop();
+}
+base::MessageLoopProxy* RenderThreadImpl::GetIOLoopProxy() {
+  return ChildProcess::current()->io_message_loop_proxy();
+}
+
+base::WaitableEvent* RenderThreadImpl::GetShutDownEvent() {
+  return ChildProcess::current()->GetShutDownEvent();
+}
+
+scoped_ptr<base::SharedMemory> RenderThreadImpl::AllocateSharedMemory(
+    uint32 size) {
+  if (!IsMainThread())
+    return scoped_ptr<base::SharedMemory>();
+  base::SharedMemoryHandle handle;
+  if (!ChildThread::Send(new ChildProcessHostMsg_SyncAllocateSharedMemory(
+      size,
+      &handle))) {
+    return scoped_ptr<base::SharedMemory>();
+  }
+  if (!base::SharedMemory::IsHandleValid(handle))
+    return scoped_ptr<base::SharedMemory>();
+  return scoped_ptr<base::SharedMemory>(new base::SharedMemory(handle, false));
+}
+
+int32 RenderThreadImpl::CreateViewCommandBuffer(
+      int32 surface_id, const GPUCreateCommandBufferConfig& init_params) {
+  int32 route_id = MSG_ROUTING_NONE;
+  ChildThread::Send(new GpuHostMsg_CreateViewCommandBuffer(
+      surface_id,
+      init_params,
+      &route_id));
+  return route_id;
+}
+
 int32 RenderThreadImpl::RoutingIDForCurrentContext() {
   int32 routing_id = MSG_ROUTING_CONTROL;
   if (v8::Context::InContext()) {
@@ -798,7 +845,7 @@
   }
 
   if (!gpu_channel_.get())
-    gpu_channel_ = new GpuChannelHost;
+    gpu_channel_ = new GpuChannelHost(this);
 
   // Ask the browser for the channel name.
   IPC::ChannelHandle channel_handle;
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index b0501bd..b69bea3 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -14,11 +14,13 @@
 #include "base/time.h"
 #include "base/timer.h"
 #include "build/build_config.h"
+#include "content/common/child_process.h"
 #include "content/common/child_thread.h"
 #include "content/common/content_export.h"
 #include "content/common/css_colors.h"
 #include "content/common/gpu/gpu_process_launch_causes.h"
 #include "content/public/renderer/render_thread.h"
+#include "content/renderer/gpu/gpu_channel_host.h"
 #include "ipc/ipc_channel_proxy.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -67,7 +69,8 @@
 // routed to the RenderThread according to the routing IDs of the messages.
 // The routing IDs correspond to RenderView instances.
 class CONTENT_EXPORT RenderThreadImpl : public content::RenderThread,
-                                        public ChildThread {
+                                        public ChildThread,
+                                        public GpuChannelHostFactory {
  public:
   static RenderThreadImpl* current();
 
@@ -118,6 +121,26 @@
   virtual void ReleaseCachedFonts() OVERRIDE;
 #endif
 
+  // GpuChannelHostFactory implementation:
+  virtual bool IsMainThread() OVERRIDE;
+  virtual bool IsIOThread() OVERRIDE;
+  virtual MessageLoop* GetMainLoop() OVERRIDE;
+  virtual base::MessageLoopProxy* GetIOLoopProxy() OVERRIDE;
+  virtual base::WaitableEvent* GetShutDownEvent() OVERRIDE;
+  virtual scoped_ptr<base::SharedMemory> AllocateSharedMemory(
+      uint32 size) OVERRIDE;
+  virtual int32 CreateViewCommandBuffer(
+      int32 surface_id,
+      const GPUCreateCommandBufferConfig& init_params) OVERRIDE;
+
+  // Synchronously establish a channel to the GPU plugin if not previously
+  // established or if it has been lost (for example if the GPU plugin crashed).
+  // If there is a pending asynchronous request, it will be completed by the
+  // time this routine returns.
+  virtual GpuChannelHost* EstablishGpuChannelSync(
+      content::CauseForGpuLaunch) OVERRIDE;
+
+
   // These methods modify how the next message is sent.  Normally, when sending
   // a synchronous message that runs a nested message loop, we need to suspend
   // callbacks into WebKit.  This involves disabling timers and deferring
@@ -149,12 +172,6 @@
 
   bool plugin_refresh_allowed() const { return plugin_refresh_allowed_; }
 
-  // Synchronously establish a channel to the GPU plugin if not previously
-  // established or if it has been lost (for example if the GPU plugin crashed).
-  // If there is a pending asynchronous request, it will be completed by the
-  // time this routine returns.
-  GpuChannelHost* EstablishGpuChannelSync(content::CauseForGpuLaunch);
-
   // Get the GPU channel. Returns NULL if the channel is not established or
   // has been lost.
   GpuChannelHost* GetGpuChannel();
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index a23022d..2489449 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1502,9 +1502,21 @@
     return webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWebView(
           attributes, webview(), direct);
   } else {
-    scoped_ptr<WebGraphicsContext3D> context(
-        new WebGraphicsContext3DCommandBufferImpl());
-    if (!context->initialize(attributes, webview(), direct))
+    int surface = direct ? surface_id() : 0;
+
+    GURL url;
+    if (webview()->mainFrame())
+      url = GURL(webview()->mainFrame()->document().url());
+
+    base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
+    if (direct)
+      swap_client = AsWeakPtr();
+
+    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
+        new WebGraphicsContext3DCommandBufferImpl(
+            surface, url, swap_client));
+
+    if (!context->Initialize(attributes))
       return NULL;
     return context.release();
   }
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 6c60ae3..66e7dde 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -31,6 +31,7 @@
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/stop_find_action.h"
 #include "content/public/renderer/render_view.h"
+#include "content/renderer/gpu/webgraphicscontext3d_command_buffer_impl.h"
 #include "content/renderer/pepper_plugin_delegate_impl.h"
 #include "content/renderer/render_widget.h"
 #include "ipc/ipc_platform_file.h"
@@ -164,6 +165,7 @@
                        public content::RenderView,
                        public webkit::npapi::WebPluginPageDelegate,
                        public webkit_media::WebMediaPlayerDelegate,
+                       public WebGraphicsContext3DSwapBuffersClient,
                        public base::SupportsWeakPtr<RenderViewImpl> {
  public:
   // Creates a new RenderView.  The parent_hwnd specifies a HWND to use as the
@@ -190,11 +192,13 @@
   // May return NULL when the view is closing.
   CONTENT_EXPORT WebKit::WebView* webview() const;
 
+  // WebGraphicsContext3DSwapBuffersClient implementation.
+
   // Called by a GraphicsContext associated with this view when swapbuffers
   // is posted, completes or is aborted.
-  void OnViewContextSwapBuffersPosted();
-  void OnViewContextSwapBuffersComplete();
-  void OnViewContextSwapBuffersAborted();
+  virtual void OnViewContextSwapBuffersPosted() OVERRIDE;
+  virtual void OnViewContextSwapBuffersComplete() OVERRIDE;
+  virtual void OnViewContextSwapBuffersAborted() OVERRIDE;
 
   int history_list_offset() const { return history_list_offset_; }
 
diff --git a/content/renderer/renderer_webkitplatformsupport_impl.cc b/content/renderer/renderer_webkitplatformsupport_impl.cc
index 5e62910..1c57670 100644
--- a/content/renderer/renderer_webkitplatformsupport_impl.cc
+++ b/content/renderer/renderer_webkitplatformsupport_impl.cc
@@ -573,9 +573,10 @@
     return webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWebView(
             attributes, NULL, false);
   } else {
-    scoped_ptr<WebGraphicsContext3D> context;
-    context.reset(new WebGraphicsContext3DCommandBufferImpl());
-    if (!context->initialize(attributes, NULL, false))
+    base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> null_client;
+    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
+        new WebGraphicsContext3DCommandBufferImpl(0, GURL(), null_client));
+    if (!context->Initialize(attributes))
       return NULL;
     return context.release();
   }