Merge "Bump up the fallback OS version number to 4.3.0"
diff --git a/android_webview/DEPS b/android_webview/DEPS
index 5f848d2..1ce4c33 100644
--- a/android_webview/DEPS
+++ b/android_webview/DEPS
@@ -8,7 +8,7 @@
   "-android_webview/lib",
 
   "+content/public/common",
-  "+gpu/command_buffer/client",
+  "+gpu",
   "+jni",
   "+net",
   "+skia",
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index ddbd1b8..299dc12 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -83,6 +83,7 @@
         '../components/components.gyp:web_contents_delegate_android',
         '../content/content.gyp:content',
         '../skia/skia.gyp:skia',
+        '../gpu/gpu.gyp:command_buffer_service',
         '../gpu/gpu.gyp:gles2_implementation',
         '../ui/gl/gl.gyp:gl',
         '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/in_process_view_renderer.cc
index f5e1762..d761124 100644
--- a/android_webview/browser/in_process_view_renderer.cc
+++ b/android_webview/browser/in_process_view_renderer.cc
@@ -16,7 +16,9 @@
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/browser/android/synchronous_compositor.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
+#include "gpu/command_buffer/service/in_process_command_buffer.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -31,6 +33,7 @@
 using base::android::AttachCurrentThread;
 using base::android::JavaRef;
 using base::android::ScopedJavaLocalRef;
+using content::BrowserThread;
 
 namespace android_webview {
 
@@ -125,8 +128,44 @@
 
 const int64 kFallbackTickTimeoutInMilliseconds = 500;
 
+class ScopedAllowGL {
+ public:
+  ScopedAllowGL();
+  ~ScopedAllowGL();
+
+  static bool IsAllowed() {
+    return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl;
+  }
+
+ private:
+  static bool allow_gl;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
+};
+
+ScopedAllowGL::ScopedAllowGL() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!allow_gl);
+  allow_gl = true;
+}
+
+ScopedAllowGL::~ScopedAllowGL() {
+  allow_gl = false;
+}
+
+bool ScopedAllowGL::allow_gl = false;
+
 }  // namespace
 
+// Called from different threads!
+static void ScheduleGpuWork() {
+  if (ScopedAllowGL::IsAllowed()) {
+    gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
+  } else {
+    // TODO: We need to request a callback with a GL context current here.
+  }
+}
+
 // static
 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
     AwDrawSWFunctionTable* table) {
@@ -135,6 +174,9 @@
       g_sw_draw_functions->is_skia_version_compatible(&SkGraphics::GetVersion);
   LOG_IF(WARNING, !g_is_skia_version_compatible)
       << "Skia versions are not compatible, rendering performance will suffer.";
+
+  gpu::InProcessCommandBuffer::SetScheduleCallback(
+      base::Bind(&ScheduleGpuWork));
 }
 
 // static
@@ -229,6 +271,8 @@
   }
 
   ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW);
+  gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
+  ScopedAllowGL allow_gl;
 
   if (attached_to_window_ && compositor_ && !hardware_initialized_) {
     TRACE_EVENT0("android_webview", "InitializeHwDraw");
@@ -462,6 +506,8 @@
 
     ScopedAppGLStateRestore state_restore(
         ScopedAppGLStateRestore::MODE_DETACH_FROM_WINDOW);
+    gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
+    ScopedAllowGL allow_gl;
     compositor_->ReleaseHwDraw();
     hardware_initialized_ = false;
   }
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc
index 4c94d1f..0e43add 100644
--- a/android_webview/lib/main/aw_main_delegate.cc
+++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -22,6 +22,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/client/gl_in_process_context.h"
+#include "gpu/command_buffer/service/in_process_command_buffer.h"
 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
 
 namespace android_webview {
@@ -45,9 +46,9 @@
 bool AwMainDelegate::BasicStartupComplete(int* exit_code) {
   content::SetContentClient(&content_client_);
 
-  gpu::GLInProcessContext::EnableVirtualizedContext();
   gpu::GLInProcessContext::SetGpuMemoryBufferFactory(
       gpu_memory_buffer_factory_.get());
+  gpu::InProcessCommandBuffer::EnableVirtualizedContext();
 
   CommandLine* cl = CommandLine::ForCurrentProcess();
   cl->AppendSwitch(switches::kEnableBeginFrameScheduling);
diff --git a/gpu/command_buffer/client/gl_in_process_context.cc b/gpu/command_buffer/client/gl_in_process_context.cc
index 2359a05..b1b5a03 100644
--- a/gpu/command_buffer/client/gl_in_process_context.cc
+++ b/gpu/command_buffer/client/gl_in_process_context.cc
@@ -4,6 +4,7 @@
 
 #include "gpu/command_buffer/client/gl_in_process_context.h"
 
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -16,36 +17,24 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/callback.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/synchronization/lock.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
 #include "gpu/command_buffer/client/image_factory.h"
 #include "gpu/command_buffer/client/transfer_buffer.h"
+#include "gpu/command_buffer/common/command_buffer.h"
 #include "gpu/command_buffer/common/constants.h"
-#include "gpu/command_buffer/common/id_allocator.h"
-#include "gpu/command_buffer/service/command_buffer_service.h"
-#include "gpu/command_buffer/service/context_group.h"
-#include "gpu/command_buffer/service/gl_context_virtual.h"
-#include "gpu/command_buffer/service/gpu_scheduler.h"
-#include "gpu/command_buffer/service/image_manager.h"
-#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "gpu/command_buffer/service/in_process_command_buffer.h"
 #include "ui/gfx/size.h"
-#include "ui/gl/gl_context.h"
 #include "ui/gl/gl_image.h"
-#include "ui/gl/gl_share_group.h"
-#include "ui/gl/gl_surface.h"
 
 namespace gpu {
 
-using gles2::ImageManager;
-
 namespace {
 
 const int32 kCommandBufferSize = 1024 * 1024;
@@ -55,56 +44,18 @@
 const size_t kMinTransferBufferSize = 1 * 256 * 1024;
 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
 
-// In the normal command buffer implementation, all commands are passed over IPC
-// to the gpu process where they are fed to the GLES2Decoder from a single
-// thread. In layout tests, any thread could call this function. GLES2Decoder,
-// and in particular the GL implementations behind it, are not generally
-// threadsafe, so we guard entry points with a mutex.
-static base::LazyInstance<base::Lock> g_decoder_lock =
-    LAZY_INSTANCE_INITIALIZER;
-
-class GLInProcessContextImpl;
-
-static base::LazyInstance<
-    std::set<GLInProcessContextImpl*> >
-        g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER;
-
-static bool g_use_virtualized_gl_context = false;
-
 static GpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL;
 
-// Also calls DetachFromThreadHack on all GLES2Decoders before the lock is
-// released to maintain the invariant that all decoders are unbound while the
-// lock is not held. This is to workaround DumpRenderTree using WGC3DIPCBI with
-// shared resources on different threads.
-// Remove this as part of crbug.com/234964.
-class AutoLockAndDecoderDetachThread {
- public:
-  AutoLockAndDecoderDetachThread(
-      base::Lock& lock,
-      const std::set<GLInProcessContextImpl*>& contexts);
-  ~AutoLockAndDecoderDetachThread();
-
- private:
-  base::AutoLock auto_lock_;
-  const std::set<GLInProcessContextImpl*>& contexts_;
-};
-
-size_t SharedContextCount() {
-  AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(),
-                                      g_all_shared_contexts.Get());
-  return g_all_shared_contexts.Get().size();
-}
-
 class GLInProcessContextImpl
     : public GLInProcessContext,
       public gles2::ImageFactory,
       public base::SupportsWeakPtr<GLInProcessContextImpl> {
  public:
-  explicit GLInProcessContextImpl(bool share_resources);
+  explicit GLInProcessContextImpl();
   virtual ~GLInProcessContextImpl();
 
   bool Initialize(bool is_offscreen,
+                  bool share_resources,
                   gfx::AcceleratedWidget window,
                   const gfx::Size& size,
                   const char* allowed_extensions,
@@ -125,67 +76,39 @@
       unsigned* image_id) OVERRIDE;
   virtual void DeleteGpuMemoryBuffer(unsigned image_id) OVERRIDE;
 
-  // Other methods:
-  gles2::GLES2Decoder* GetDecoder();
-  bool GetBufferChanged(int32 transfer_buffer_id);
-  void PumpCommands();
-  void OnResizeView(gfx::Size size, float scale_factor);
-  void OnContextLost();
-
  private:
   void Destroy();
-  bool IsCommandBufferContextLost();
   void PollQueryCallbacks();
   void CallQueryCallback(size_t index);
-  bool MakeCurrent();
+  void OnContextLost(const base::Closure& callback);
+  void OnSignalSyncPoint(const base::Closure& callback);
 
-  gles2::ImageManager* GetImageManager();
-
-  base::Closure context_lost_callback_;
-  scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
-  scoped_ptr<CommandBuffer> command_buffer_;
-  scoped_ptr<GpuScheduler> gpu_scheduler_;
-  scoped_ptr<gles2::GLES2Decoder> decoder_;
-  scoped_refptr<gfx::GLContext> context_;
-  scoped_refptr<gfx::GLSurface> surface_;
   scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_;
   scoped_ptr<TransferBuffer> transfer_buffer_;
   scoped_ptr<gles2::GLES2Implementation> gles2_implementation_;
-  bool share_resources_;
-  bool context_lost_;
+  scoped_ptr<InProcessCommandBuffer> command_buffer_;
 
   typedef std::pair<unsigned, base::Closure> QueryCallback;
   std::vector<QueryCallback> query_callbacks_;
 
-  std::vector<base::Closure> signal_sync_point_callbacks_;
+  unsigned int share_group_id_;
+  bool context_lost_;
 
   DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl);
 };
 
-AutoLockAndDecoderDetachThread::AutoLockAndDecoderDetachThread(
-    base::Lock& lock,
-    const std::set<GLInProcessContextImpl*>& contexts)
-    : auto_lock_(lock),
-      contexts_(contexts) {
-}
+base::LazyInstance<base::Lock> g_all_shared_contexts_lock =
+    LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<std::set<GLInProcessContextImpl*> > g_all_shared_contexts =
+    LAZY_INSTANCE_INITIALIZER;
 
-void DetachThread(GLInProcessContextImpl* context) {
-  if (context->GetDecoder())
-    context->GetDecoder()->DetachFromThreadHack();
-}
-
-AutoLockAndDecoderDetachThread::~AutoLockAndDecoderDetachThread() {
-  std::for_each(contexts_.begin(),
-                contexts_.end(),
-                &DetachThread);
+size_t SharedContextCount() {
+  base::AutoLock lock(g_all_shared_contexts_lock.Get());
+  return g_all_shared_contexts.Get().size();
 }
 
 scoped_ptr<GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer(
     int width, int height, GLenum internalformat, unsigned int* image_id) {
-  // We're taking the lock here because we're accessing the ContextGroup's
-  // shared IdManager.
-  AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(),
-                                      g_all_shared_contexts.Get());
   scoped_ptr<GpuMemoryBuffer> buffer(
       g_gpu_memory_buffer_factory->CreateGpuMemoryBuffer(width,
                                                          height,
@@ -193,111 +116,58 @@
   if (!buffer)
     return scoped_ptr<GpuMemoryBuffer>();
 
-  scoped_refptr<gfx::GLImage> gl_image =
-      gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer->GetNativeBuffer(),
-                                                    gfx::Size(width, height));
-  *image_id = decoder_->GetContextGroup()
-      ->GetIdAllocator(gles2::id_namespaces::kImages)->AllocateID();
-  GetImageManager()->AddImage(gl_image.get(), *image_id);
+  *image_id = command_buffer_->CreateImageForGpuMemoryBuffer(
+      buffer->GetNativeBuffer(), gfx::Size(width, height));
   return buffer.Pass();
 }
 
 void GLInProcessContextImpl::DeleteGpuMemoryBuffer(unsigned int image_id) {
-  // We're taking the lock here because we're accessing the ContextGroup's
-  // shared ImageManager.
-  AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(),
-                                      g_all_shared_contexts.Get());
-  GetImageManager()->RemoveImage(image_id);
-  decoder_->GetContextGroup()->GetIdAllocator(gles2::id_namespaces::kImages)
-      ->FreeID(image_id);
+  command_buffer_->RemoveImage(image_id);
 }
 
-GLInProcessContextImpl::GLInProcessContextImpl(bool share_resources)
-    : share_resources_(share_resources),
-      context_lost_(false) {
-}
+GLInProcessContextImpl::GLInProcessContextImpl()
+    : share_group_id_(0), context_lost_(false) {}
 
 GLInProcessContextImpl::~GLInProcessContextImpl() {
-  Destroy();
-}
-
-bool GLInProcessContextImpl::MakeCurrent() {
-  if (decoder_->MakeCurrent())
-    return true;
-  DLOG(ERROR) << "Context lost because MakeCurrent failed.";
-  command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
-  command_buffer_->SetParseError(gpu::error::kLostContext);
-  return false;
-}
-
-void GLInProcessContextImpl::PumpCommands() {
   {
-    AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(),
-                                        g_all_shared_contexts.Get());
-    if (!MakeCurrent())
-      return;
-    gpu_scheduler_->PutChanged();
-    CommandBuffer::State state = command_buffer_->GetState();
-    DCHECK((!error::IsError(state.error) && !context_lost_) ||
-           (error::IsError(state.error) && context_lost_));
+    base::AutoLock lock(g_all_shared_contexts_lock.Get());
+    g_all_shared_contexts.Get().erase(this);
   }
-
-  if (!context_lost_ && signal_sync_point_callbacks_.size()) {
-    for (size_t n = 0; n < signal_sync_point_callbacks_.size(); n++) {
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-                                             signal_sync_point_callbacks_[n]);
-    }
-  }
-  signal_sync_point_callbacks_.clear();
-}
-
-bool GLInProcessContextImpl::GetBufferChanged(int32 transfer_buffer_id) {
-  return gpu_scheduler_->SetGetBuffer(transfer_buffer_id);
+  Destroy();
 }
 
 void GLInProcessContextImpl::SignalSyncPoint(unsigned sync_point,
                                              const base::Closure& callback) {
   DCHECK(!callback.is_null());
-  signal_sync_point_callbacks_.push_back(callback);
-}
-
-bool GLInProcessContextImpl::IsCommandBufferContextLost() {
-  if (context_lost_ || !command_buffer_) {
-    return true;
-  }
-  CommandBuffer::State state = command_buffer_->GetState();
-  return error::IsError(state.error);
-}
-
-gles2::GLES2Decoder* GLInProcessContextImpl::GetDecoder() {
-  return decoder_.get();
-}
-
-void GLInProcessContextImpl::OnResizeView(gfx::Size size, float scale_factor) {
-  DCHECK(!surface_->IsOffscreen());
-  surface_->Resize(size);
+  base::Closure wrapped_callback = base::Bind(
+      &GLInProcessContextImpl::OnSignalSyncPoint, AsWeakPtr(), callback);
+  command_buffer_->SignalSyncPoint(sync_point, wrapped_callback);
 }
 
 gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() {
   return gles2_implementation_.get();
 }
 
-gles2::ImageManager* GLInProcessContextImpl::GetImageManager() {
-  return decoder_->GetContextGroup()->image_manager();
+void GLInProcessContextImpl::OnContextLost(const base::Closure& callback) {
+  context_lost_ = true;
+  callback.Run();
+}
+
+void GLInProcessContextImpl::OnSignalSyncPoint(const base::Closure& callback) {
+  // TODO: Should it always trigger callbacks?
+  if (!context_lost_)
+    callback.Run();
 }
 
 bool GLInProcessContextImpl::Initialize(
     bool is_offscreen,
+    bool share_resources,
     gfx::AcceleratedWidget window,
     const gfx::Size& size,
     const char* allowed_extensions,
     const int32* attrib_list,
     gfx::GpuPreference gpu_preference,
     const base::Closure& context_lost_callback) {
-  // Use one share group for all contexts.
-  CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group,
-                         (new gfx::GLShareGroup));
-
   DCHECK(size.width() >= 0 && size.height() >= 0);
 
   std::vector<int32> attribs;
@@ -327,128 +197,50 @@
     }
   }
 
-  {
-    TransferBufferManager* manager = new TransferBufferManager();
-    transfer_buffer_manager_.reset(manager);
-    manager->Initialize();
+  base::Closure wrapped_callback =
+      base::Bind(&GLInProcessContextImpl::OnContextLost,
+                 AsWeakPtr(),
+                 context_lost_callback);
+  command_buffer_.reset(new InProcessCommandBuffer());
+
+  scoped_ptr<base::AutoLock> scoped_shared_context_lock;
+  scoped_refptr<gles2::ShareGroup> share_group;
+  if (share_resources) {
+    scoped_shared_context_lock.reset(
+        new base::AutoLock(g_all_shared_contexts_lock.Get()));
+    for (std::set<GLInProcessContextImpl*>::const_iterator it =
+             g_all_shared_contexts.Get().begin();
+         it != g_all_shared_contexts.Get().end();
+         it++) {
+      const GLInProcessContextImpl* context = *it;
+      if (!context->context_lost_) {
+        share_group = context->gles2_implementation_->share_group();
+        DCHECK(share_group);
+        share_group_id_ = context->share_group_id_;
+        break;
+      }
+      share_group_id_ = std::max(share_group_id_, context->share_group_id_);
+    }
+    if (!share_group && !++share_group_id_)
+        ++share_group_id_;
   }
-
-  scoped_ptr<CommandBufferService> command_buffer(
-      new CommandBufferService(transfer_buffer_manager_.get()));
-  command_buffer->SetPutOffsetChangeCallback(base::Bind(
-      &GLInProcessContextImpl::PumpCommands, base::Unretained(this)));
-  command_buffer->SetGetBufferChangeCallback(base::Bind(
-      &GLInProcessContextImpl::GetBufferChanged, base::Unretained(this)));
-  command_buffer->SetParseErrorCallback(base::Bind(
-      &GLInProcessContextImpl::OnContextLost, base::Unretained(this)));
-
-  command_buffer_ = command_buffer.Pass();
-  if (!command_buffer_->Initialize()) {
-    LOG(ERROR) << "Could not initialize command buffer.";
-    Destroy();
-    return false;
-  }
-
-  GLInProcessContextImpl* context_group = NULL;
-
-  {
-    AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(),
-                                        g_all_shared_contexts.Get());
-    if (share_resources_ && !g_all_shared_contexts.Get().empty()) {
-      for (std::set<GLInProcessContextImpl*>::iterator it =
-               g_all_shared_contexts.Get().begin();
-           it != g_all_shared_contexts.Get().end();
-           ++it) {
-        if (!(*it)->IsCommandBufferContextLost()) {
-          context_group = *it;
-          break;
-        }
-      }
-      if (!context_group)
-        share_group = new gfx::GLShareGroup;
-    }
-
-    // TODO(gman): This needs to be true if this is Pepper.
-    bool bind_generates_resource = false;
-    decoder_.reset(gles2::GLES2Decoder::Create(
-        context_group ? context_group->decoder_->GetContextGroup()
-                      : new gles2::ContextGroup(
-                            NULL, NULL, NULL, NULL, bind_generates_resource)));
-
-    gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(),
-                                          decoder_.get(),
-                                          decoder_.get()));
-
-    decoder_->set_engine(gpu_scheduler_.get());
-
-    if (is_offscreen)
-      surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
-    else
-      surface_ = gfx::GLSurface::CreateViewGLSurface(window);
-
-    if (!surface_.get()) {
-      LOG(ERROR) << "Could not create GLSurface.";
-      Destroy();
-      return false;
-    }
-
-    if (g_use_virtualized_gl_context) {
-      context_ = share_group->GetSharedContext();
-      if (!context_.get()) {
-        context_ = gfx::GLContext::CreateGLContext(
-            share_group.get(), surface_.get(), gpu_preference);
-        share_group->SetSharedContext(context_.get());
-      }
-
-      context_ = new GLContextVirtual(
-          share_group.get(), context_.get(), decoder_->AsWeakPtr());
-      if (context_->Initialize(surface_.get(), gpu_preference)) {
-        VLOG(1) << "Created virtual GL context.";
-      } else {
-        context_ = NULL;
-      }
-    } else {
-      context_ = gfx::GLContext::CreateGLContext(share_group.get(),
-                                                 surface_.get(),
-                                                 gpu_preference);
-    }
-
-    if (!context_.get()) {
-      LOG(ERROR) << "Could not create GLContext.";
-      Destroy();
-      return false;
-    }
-
-    if (!context_->MakeCurrent(surface_.get())) {
-      LOG(ERROR) << "Could not make context current.";
-      Destroy();
-      return false;
-    }
-
-    gles2::DisallowedFeatures disallowed_features;
-    disallowed_features.swap_buffer_complete_callback = true;
-    disallowed_features.gpu_memory_manager = true;
-    if (!decoder_->Initialize(surface_,
-                              context_,
-                              is_offscreen,
+  if (!command_buffer_->Initialize(is_offscreen,
+                              share_resources,
+                              window,
                               size,
-                              disallowed_features,
                               allowed_extensions,
-                              attribs)) {
-      LOG(ERROR) << "Could not initialize decoder.";
-      Destroy();
-      return false;
-    }
-
-    if (!is_offscreen) {
-      decoder_->SetResizeCallback(base::Bind(
-          &GLInProcessContextImpl::OnResizeView, base::Unretained(this)));
-    }
+                              attribs,
+                              gpu_preference,
+                              wrapped_callback,
+                              share_group_id_)) {
+    LOG(INFO) << "Failed to initialize InProcessCommmandBuffer";
+    return false;
   }
 
   // Create the GLES2 helper, which writes the command buffer protocol.
   gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
   if (!gles2_helper_->Initialize(kCommandBufferSize)) {
+    LOG(INFO) << "Failed to initialize GLES2CmdHelper";
     Destroy();
     return false;
   }
@@ -459,11 +251,16 @@
   // Create the object exposing the OpenGL API.
   gles2_implementation_.reset(new gles2::GLES2Implementation(
       gles2_helper_.get(),
-      context_group ? context_group->GetImplementation()->share_group() : NULL,
+      share_group,
       transfer_buffer_.get(),
       false,
       this));
 
+  if (share_resources) {
+    g_all_shared_contexts.Get().insert(this);
+    scoped_shared_context_lock.reset();
+  }
+
   if (!gles2_implementation_->Initialize(
       kStartTransferBufferSize,
       kMinTransferBufferSize,
@@ -471,13 +268,6 @@
     return false;
   }
 
-  if (share_resources_) {
-    AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(),
-                                        g_all_shared_contexts.Get());
-    g_all_shared_contexts.Pointer()->insert(this);
-  }
-
-  context_lost_callback_ = context_lost_callback;
   return true;
 }
 
@@ -486,8 +276,6 @@
     CallQueryCallback(0);
   }
 
-  bool context_lost = IsCommandBufferContextLost();
-
   if (gles2_implementation_) {
     // First flush the context to ensure that any pending frees of resources
     // are completed. Otherwise, if this context is part of a share group,
@@ -502,28 +290,6 @@
   transfer_buffer_.reset();
   gles2_helper_.reset();
   command_buffer_.reset();
-
-  AutoLockAndDecoderDetachThread lock(g_decoder_lock.Get(),
-                                      g_all_shared_contexts.Get());
-  if (decoder_) {
-    decoder_->Destroy(!context_lost);
-  }
-
-  g_all_shared_contexts.Pointer()->erase(this);
-}
-
-void GLInProcessContextImpl::OnContextLost() {
-  if (!context_lost_callback_.is_null())
-    context_lost_callback_.Run();
-
-  context_lost_ = true;
-  if (share_resources_) {
-      for (std::set<GLInProcessContextImpl*>::iterator it =
-               g_all_shared_contexts.Get().begin();
-           it != g_all_shared_contexts.Get().end();
-           ++it)
-        (*it)->context_lost_ = true;
-  }
 }
 
 void GLInProcessContextImpl::CallQueryCallback(size_t index) {
@@ -534,6 +300,7 @@
   query_callback.second.Run();
 }
 
+// TODO(sievers): Move this to the service side
 void GLInProcessContextImpl::PollQueryCallbacks() {
   for (size_t i = 0; i < query_callbacks_.size();) {
     unsigned query = query_callbacks_[i].first;
@@ -582,9 +349,10 @@
     gfx::GpuPreference gpu_preference,
     const base::Closure& callback) {
   scoped_ptr<GLInProcessContextImpl> context(
-      new GLInProcessContextImpl(share_resources));
+      new GLInProcessContextImpl());
   if (!context->Initialize(
       is_offscreen,
+      share_resources,
       window,
       size,
       allowed_extensions,
@@ -603,10 +371,4 @@
   g_gpu_memory_buffer_factory = factory;
 }
 
-// static
-void GLInProcessContext::EnableVirtualizedContext() {
-  DCHECK_EQ(0u, SharedContextCount());
-  g_use_virtualized_gl_context = true;
-}
-
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/gl_in_process_context.h b/gpu/command_buffer/client/gl_in_process_context.h
index 9e38b1c..2d0754b 100644
--- a/gpu/command_buffer/client/gl_in_process_context.h
+++ b/gpu/command_buffer/client/gl_in_process_context.h
@@ -30,10 +30,6 @@
   // Must be called before any GLInProcessContext instances are created.
   static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory);
 
-  // Must be called before any GLInProcessContext instances are created.
-  // Default value is false.
-  static void EnableVirtualizedContext();
-
   // GLInProcessContext configuration attributes. These are the same as used by
   // EGL. Attributes are matched using a closest fit algorithm.
   enum Attribute {
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
new file mode 100644
index 0000000..e8219a1
--- /dev/null
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -0,0 +1,700 @@
+// Copyright (c) 2012 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 "gpu/command_buffer/service/in_process_command_buffer.h"
+
+#include <queue>
+#include <utility>
+
+#include <GLES2/gl2.h>
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES 1
+#endif
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/threading/thread.h"
+#include "gpu/command_buffer/common/id_allocator.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/gl_context_virtual.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/image_manager.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "ui/gfx/size.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/gl_share_group.h"
+#include "ui/gl/gl_surface.h"
+
+namespace gpu {
+
+namespace {
+
+static base::LazyInstance<std::set<InProcessCommandBuffer*> >
+    g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER;
+
+static bool g_use_virtualized_gl_context = false;
+static bool g_uses_explicit_scheduling = false;
+
+template <typename T>
+static void RunTaskWithResult(base::Callback<T(void)> task,
+                              T* result,
+                              base::WaitableEvent* completion) {
+  *result = task.Run();
+  completion->Signal();
+}
+
+class GpuInProcessThread
+    : public base::Thread,
+      public base::RefCountedThreadSafe<GpuInProcessThread> {
+ public:
+  GpuInProcessThread();
+
+ private:
+  friend class base::RefCountedThreadSafe<GpuInProcessThread>;
+  virtual ~GpuInProcessThread();
+
+  DISALLOW_COPY_AND_ASSIGN(GpuInProcessThread);
+};
+
+GpuInProcessThread::GpuInProcessThread() : base::Thread("GpuThread") {
+  Start();
+}
+
+GpuInProcessThread::~GpuInProcessThread() {
+  Stop();
+}
+
+// Used with explicit scheduling when there is no dedicated GPU thread.
+class GpuCommandQueue {
+ public:
+  GpuCommandQueue();
+  ~GpuCommandQueue();
+
+  void QueueTask(const base::Closure& task);
+  void RunTasks();
+  void SetScheduleCallback(const base::Closure& callback);
+
+ private:
+  base::Lock tasks_lock_;
+  std::queue<base::Closure> tasks_;
+  base::Closure schedule_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuCommandQueue);
+};
+
+GpuCommandQueue::GpuCommandQueue() {}
+
+GpuCommandQueue::~GpuCommandQueue() {
+  base::AutoLock lock(tasks_lock_);
+  DCHECK(tasks_.empty());
+}
+
+void GpuCommandQueue::QueueTask(const base::Closure& task) {
+  {
+    base::AutoLock lock(tasks_lock_);
+    tasks_.push(task);
+  }
+
+  DCHECK(!schedule_callback_.is_null());
+  schedule_callback_.Run();
+}
+
+void GpuCommandQueue::RunTasks() {
+  size_t num_tasks;
+  {
+    base::AutoLock lock(tasks_lock_);
+    num_tasks = tasks_.size();
+  }
+
+  while (num_tasks) {
+    base::Closure task;
+    {
+      base::AutoLock lock(tasks_lock_);
+      task = tasks_.front();
+      tasks_.pop();
+      num_tasks = tasks_.size();
+    }
+
+    task.Run();
+  }
+}
+
+void GpuCommandQueue::SetScheduleCallback(const base::Closure& callback) {
+  DCHECK(schedule_callback_.is_null());
+  schedule_callback_ = callback;
+}
+
+static base::LazyInstance<GpuCommandQueue> g_gpu_queue =
+    LAZY_INSTANCE_INITIALIZER;
+
+class SchedulerClientBase : public InProcessCommandBuffer::SchedulerClient {
+ public:
+  explicit SchedulerClientBase(bool need_thread);
+  virtual ~SchedulerClientBase();
+
+  static bool HasClients();
+
+ protected:
+  scoped_refptr<GpuInProcessThread> thread_;
+
+ private:
+  static base::LazyInstance<std::set<SchedulerClientBase*> > all_clients_;
+  static base::LazyInstance<base::Lock> all_clients_lock_;
+};
+
+base::LazyInstance<std::set<SchedulerClientBase*> >
+    SchedulerClientBase::all_clients_ = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::Lock> SchedulerClientBase::all_clients_lock_ =
+    LAZY_INSTANCE_INITIALIZER;
+
+SchedulerClientBase::SchedulerClientBase(bool need_thread) {
+  base::AutoLock(all_clients_lock_.Get());
+  if (need_thread) {
+    if (!all_clients_.Get().empty()) {
+      SchedulerClientBase* other = *all_clients_.Get().begin();
+      thread_ = other->thread_;
+      DCHECK(thread_.get());
+    } else {
+      thread_ = new GpuInProcessThread;
+    }
+  }
+  all_clients_.Get().insert(this);
+}
+
+SchedulerClientBase::~SchedulerClientBase() {
+  base::AutoLock(all_clients_lock_.Get());
+  all_clients_.Get().erase(this);
+}
+
+bool SchedulerClientBase::HasClients() {
+  base::AutoLock(all_clients_lock_.Get());
+  return !all_clients_.Get().empty();
+}
+
+// A client that talks to the GPU thread
+class ThreadClient : public SchedulerClientBase {
+ public:
+  ThreadClient();
+  virtual void QueueTask(const base::Closure& task) OVERRIDE;
+};
+
+ThreadClient::ThreadClient() : SchedulerClientBase(true) {
+  DCHECK(thread_.get());
+}
+
+void ThreadClient::QueueTask(const base::Closure& task) {
+  thread_->message_loop()->PostTask(FROM_HERE, task);
+}
+
+// A client that talks to the GpuCommandQueue
+class QueueClient : public SchedulerClientBase {
+ public:
+  QueueClient();
+  virtual void QueueTask(const base::Closure& task) OVERRIDE;
+};
+
+QueueClient::QueueClient() : SchedulerClientBase(false) {
+  DCHECK(!thread_.get());
+}
+
+void QueueClient::QueueTask(const base::Closure& task) {
+  g_gpu_queue.Get().QueueTask(task);
+}
+
+static scoped_ptr<InProcessCommandBuffer::SchedulerClient>
+CreateSchedulerClient() {
+  scoped_ptr<InProcessCommandBuffer::SchedulerClient> client;
+  if (g_uses_explicit_scheduling)
+    client.reset(new QueueClient);
+  else
+    client.reset(new ThreadClient);
+
+  return client.Pass();
+}
+
+class ScopedEvent {
+ public:
+  ScopedEvent(base::WaitableEvent* event) : event_(event) {}
+  ~ScopedEvent() { event_->Signal(); }
+
+ private:
+  base::WaitableEvent* event_;
+};
+
+}  // anonyous namespace
+
+InProcessCommandBuffer::InProcessCommandBuffer()
+    : context_lost_(false),
+      share_group_id_(0),
+      last_put_offset_(-1),
+      flush_event_(false, false),
+      queue_(CreateSchedulerClient()) {}
+
+InProcessCommandBuffer::~InProcessCommandBuffer() {
+  Destroy();
+}
+
+bool InProcessCommandBuffer::IsContextLost() {
+  if (context_lost_ || !command_buffer_) {
+    return true;
+  }
+  CommandBuffer::State state = GetState();
+  return error::IsError(state.error);
+}
+
+void InProcessCommandBuffer::OnResizeView(gfx::Size size, float scale_factor) {
+  DCHECK(!surface_->IsOffscreen());
+  surface_->Resize(size);
+}
+
+bool InProcessCommandBuffer::MakeCurrent() {
+  command_buffer_lock_.AssertAcquired();
+
+  if (!context_lost_ && decoder_->MakeCurrent())
+    return true;
+  DLOG(ERROR) << "Context lost because MakeCurrent failed.";
+  command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
+  command_buffer_->SetParseError(gpu::error::kLostContext);
+  return false;
+}
+
+void InProcessCommandBuffer::PumpCommands() {
+  ScopedEvent handle_flush(&flush_event_);
+  command_buffer_lock_.AssertAcquired();
+
+  if (!MakeCurrent())
+    return;
+
+  gpu_scheduler_->PutChanged();
+  CommandBuffer::State state = command_buffer_->GetState();
+  DCHECK((!error::IsError(state.error) && !context_lost_) ||
+         (error::IsError(state.error) && context_lost_));
+}
+
+bool InProcessCommandBuffer::GetBufferChanged(int32 transfer_buffer_id) {
+  command_buffer_lock_.AssertAcquired();
+  command_buffer_->SetGetBuffer(transfer_buffer_id);
+  return true;
+}
+
+bool InProcessCommandBuffer::Initialize(
+    bool is_offscreen,
+    bool share_resources,
+    gfx::AcceleratedWidget window,
+    const gfx::Size& size,
+    const char* allowed_extensions,
+    const std::vector<int32>& attribs,
+    gfx::GpuPreference gpu_preference,
+    const base::Closure& context_lost_callback,
+    unsigned int share_group_id) {
+
+  share_resources_ = share_resources;
+  context_lost_callback_ = WrapCallback(context_lost_callback);
+  share_group_id_ = share_group_id;
+
+  base::WaitableEvent completion(true, false);
+  bool result;
+  base::Callback<bool(void)> init_task =
+      base::Bind(&InProcessCommandBuffer::InitializeOnGpuThread,
+                 base::Unretained(this),
+                 is_offscreen,
+                 window,
+                 size,
+                 allowed_extensions,
+                 attribs,
+                 gpu_preference);
+  QueueTask(
+      base::Bind(&RunTaskWithResult<bool>, init_task, &result, &completion));
+  completion.Wait();
+  return result;
+}
+
+bool InProcessCommandBuffer::InitializeOnGpuThread(
+    bool is_offscreen,
+    gfx::AcceleratedWidget window,
+    const gfx::Size& size,
+    const char* allowed_extensions,
+    const std::vector<int32>& attribs,
+    gfx::GpuPreference gpu_preference) {
+  // Use one share group for all contexts.
+  CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group,
+                         (new gfx::GLShareGroup));
+
+  DCHECK(size.width() >= 0 && size.height() >= 0);
+
+  TransferBufferManager* manager = new TransferBufferManager();
+  transfer_buffer_manager_.reset(manager);
+  manager->Initialize();
+
+  scoped_ptr<CommandBufferService> command_buffer(
+      new CommandBufferService(transfer_buffer_manager_.get()));
+  command_buffer->SetPutOffsetChangeCallback(base::Bind(
+      &InProcessCommandBuffer::PumpCommands, base::Unretained(this)));
+  command_buffer->SetParseErrorCallback(base::Bind(
+      &InProcessCommandBuffer::OnContextLost, base::Unretained(this)));
+
+  if (!command_buffer->Initialize()) {
+    LOG(ERROR) << "Could not initialize command buffer.";
+    DestroyOnGpuThread();
+    return false;
+  }
+
+  InProcessCommandBuffer* context_group = NULL;
+
+  if (share_resources_ && !g_all_shared_contexts.Get().empty()) {
+    DCHECK(share_group_id_);
+    for (std::set<InProcessCommandBuffer*>::iterator it =
+             g_all_shared_contexts.Get().begin();
+         it != g_all_shared_contexts.Get().end();
+         ++it) {
+      if ((*it)->share_group_id_ == share_group_id_) {
+        context_group = *it;
+        DCHECK(context_group->share_resources_);
+        context_lost_ = context_group->IsContextLost();
+        break;
+      }
+    }
+    if (!context_group)
+      share_group = new gfx::GLShareGroup;
+  }
+
+  bool bind_generates_resource = false;
+  decoder_.reset(gles2::GLES2Decoder::Create(
+      context_group ? context_group->decoder_->GetContextGroup()
+                    : new gles2::ContextGroup(
+                          NULL, NULL, NULL, NULL, bind_generates_resource)));
+
+  gpu_scheduler_.reset(
+      new GpuScheduler(command_buffer.get(), decoder_.get(), decoder_.get()));
+  command_buffer->SetGetBufferChangeCallback(base::Bind(
+      &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
+  command_buffer_ = command_buffer.Pass();
+
+  decoder_->set_engine(gpu_scheduler_.get());
+
+  if (is_offscreen)
+    surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
+  else
+    surface_ = gfx::GLSurface::CreateViewGLSurface(window);
+
+  if (!surface_.get()) {
+    LOG(ERROR) << "Could not create GLSurface.";
+    DestroyOnGpuThread();
+    return false;
+  }
+
+  if (g_use_virtualized_gl_context) {
+    context_ = share_group->GetSharedContext();
+    if (!context_.get()) {
+      context_ = gfx::GLContext::CreateGLContext(
+          share_group.get(), surface_.get(), gpu_preference);
+      share_group->SetSharedContext(context_.get());
+    }
+
+    context_ = new GLContextVirtual(
+        share_group.get(), context_.get(), decoder_->AsWeakPtr());
+    if (context_->Initialize(surface_.get(), gpu_preference)) {
+      VLOG(1) << "Created virtual GL context.";
+    } else {
+      context_ = NULL;
+    }
+  } else {
+    context_ = gfx::GLContext::CreateGLContext(
+        share_group.get(), surface_.get(), gpu_preference);
+  }
+
+  if (!context_.get()) {
+    LOG(ERROR) << "Could not create GLContext.";
+    DestroyOnGpuThread();
+    return false;
+  }
+
+  if (!context_->MakeCurrent(surface_.get())) {
+    LOG(ERROR) << "Could not make context current.";
+    DestroyOnGpuThread();
+    return false;
+  }
+
+  gles2::DisallowedFeatures disallowed_features;
+  disallowed_features.swap_buffer_complete_callback = true;
+  disallowed_features.gpu_memory_manager = true;
+  if (!decoder_->Initialize(surface_,
+                            context_,
+                            is_offscreen,
+                            size,
+                            disallowed_features,
+                            allowed_extensions,
+                            attribs)) {
+    LOG(ERROR) << "Could not initialize decoder.";
+    DestroyOnGpuThread();
+    return false;
+  }
+
+  if (!is_offscreen) {
+    decoder_->SetResizeCallback(base::Bind(
+        &InProcessCommandBuffer::OnResizeView, base::Unretained(this)));
+  }
+
+  if (share_resources_) {
+    g_all_shared_contexts.Pointer()->insert(this);
+  }
+
+  return true;
+}
+
+void InProcessCommandBuffer::Destroy() {
+  base::WaitableEvent completion(true, false);
+  bool result;
+  base::Callback<bool(void)> destroy_task = base::Bind(
+      &InProcessCommandBuffer::DestroyOnGpuThread, base::Unretained(this));
+  QueueTask(
+      base::Bind(&RunTaskWithResult<bool>, destroy_task, &result, &completion));
+  completion.Wait();
+}
+
+bool InProcessCommandBuffer::DestroyOnGpuThread() {
+  command_buffer_.reset();
+  // Clean up GL resources if possible.
+  bool have_context = context_ && context_->MakeCurrent(surface_);
+  if (decoder_) {
+    decoder_->Destroy(have_context);
+    decoder_.reset();
+  }
+  context_ = NULL;
+  surface_ = NULL;
+
+  g_all_shared_contexts.Pointer()->erase(this);
+  return true;
+}
+
+unsigned int InProcessCommandBuffer::CreateImageForGpuMemoryBuffer(
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size) {
+  unsigned int image_id;
+  {
+    // TODO: ID allocation should go through CommandBuffer
+    base::AutoLock lock(command_buffer_lock_);
+    gles2::ContextGroup* group = decoder_->GetContextGroup();
+    image_id =
+        group->GetIdAllocator(gles2::id_namespaces::kImages)->AllocateID();
+  }
+  base::Closure image_task =
+      base::Bind(&InProcessCommandBuffer::CreateImageOnGpuThread,
+                 base::Unretained(this), buffer, size, image_id);
+  QueueTask(image_task);
+  return image_id;
+}
+
+void InProcessCommandBuffer::CreateImageOnGpuThread(
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned int image_id) {
+  scoped_refptr<gfx::GLImage> gl_image =
+      gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer, size);
+   decoder_->GetContextGroup()->image_manager()->AddImage(gl_image, image_id);
+}
+
+void InProcessCommandBuffer::RemoveImage(unsigned int image_id) {
+  {
+    // TODO: ID allocation should go through CommandBuffer
+    base::AutoLock lock(command_buffer_lock_);
+    gles2::ContextGroup* group = decoder_->GetContextGroup();
+    group->GetIdAllocator(gles2::id_namespaces::kImages)->FreeID(image_id);
+  }
+  base::Closure image_manager_task =
+      base::Bind(&InProcessCommandBuffer::RemoveImageOnGpuThread,
+                 base::Unretained(this),
+                 image_id);
+  QueueTask(image_manager_task);
+}
+
+void InProcessCommandBuffer::RemoveImageOnGpuThread(unsigned int image_id) {
+  decoder_->GetContextGroup()->image_manager()->RemoveImage(image_id);
+}
+
+void InProcessCommandBuffer::OnContextLost() {
+  if (!context_lost_callback_.is_null())
+    context_lost_callback_.Run();
+
+  context_lost_ = true;
+  if (share_resources_) {
+    for (std::set<InProcessCommandBuffer*>::iterator it =
+             g_all_shared_contexts.Get().begin();
+         it != g_all_shared_contexts.Get().end();
+         ++it) {
+      (*it)->context_lost_ = true;
+    }
+  }
+}
+
+CommandBuffer::State InProcessCommandBuffer::GetStateFast() {
+  base::AutoLock lock(command_buffer_lock_);
+  return last_state_ = command_buffer_->GetState();
+}
+
+CommandBuffer::State InProcessCommandBuffer::GetState() {
+  return GetStateFast();
+}
+
+CommandBuffer::State InProcessCommandBuffer::GetLastState() {
+  return last_state_;
+}
+
+int32 InProcessCommandBuffer::GetLastToken() { return last_state_.token; }
+
+void InProcessCommandBuffer::FlushOnGpuThread(int32 put_offset) {
+  base::AutoLock lock(command_buffer_lock_);
+  command_buffer_->Flush(put_offset);
+}
+
+void InProcessCommandBuffer::Flush(int32 put_offset) {
+  if (last_state_.error != gpu::error::kNoError)
+    return;
+
+  if (last_put_offset_ == put_offset)
+    return;
+
+  last_put_offset_ = put_offset;
+  base::Closure task = base::Bind(&InProcessCommandBuffer::FlushOnGpuThread,
+                                  base::Unretained(this),
+                                  put_offset);
+  QueueTask(task);
+}
+
+CommandBuffer::State InProcessCommandBuffer::FlushSync(int32 put_offset,
+                                                       int32 last_known_get) {
+  if (put_offset == last_known_get || last_state_.error != gpu::error::kNoError)
+    return last_state_;
+
+  Flush(put_offset);
+  GetStateFast();
+  while (last_known_get == last_state_.get_offset &&
+         last_state_.error == gpu::error::kNoError) {
+    flush_event_.Wait();
+    GetStateFast();
+  }
+
+  return last_state_;
+}
+
+void InProcessCommandBuffer::SetGetBuffer(int32 shm_id) {
+  if (last_state_.error != gpu::error::kNoError)
+    return;
+
+  {
+    base::AutoLock lock(command_buffer_lock_);
+    command_buffer_->SetGetBuffer(shm_id);
+    last_put_offset_ = 0;
+  }
+  GetStateFast();
+}
+
+gpu::Buffer InProcessCommandBuffer::CreateTransferBuffer(size_t size,
+                                                         int32* id) {
+  base::AutoLock lock(command_buffer_lock_);
+  return command_buffer_->CreateTransferBuffer(size, id);
+}
+
+void InProcessCommandBuffer::DestroyTransferBuffer(int32 id) {
+  base::Closure task = base::Bind(&CommandBuffer::DestroyTransferBuffer,
+                                  base::Unretained(command_buffer_.get()),
+                                  id);
+
+  QueueTask(task);
+}
+
+gpu::Buffer InProcessCommandBuffer::GetTransferBuffer(int32 id) {
+  NOTREACHED();
+  return gpu::Buffer();
+}
+
+uint32 InProcessCommandBuffer::InsertSyncPoint() {
+  NOTREACHED();
+  return 0;
+}
+void InProcessCommandBuffer::SignalSyncPoint(unsigned sync_point,
+                                             const base::Closure& callback) {
+  QueueTask(WrapCallback(callback));
+}
+
+gpu::error::Error InProcessCommandBuffer::GetLastError() {
+  return last_state_.error;
+}
+
+bool InProcessCommandBuffer::Initialize() {
+  NOTREACHED();
+  return false;
+}
+
+void InProcessCommandBuffer::SetGetOffset(int32 get_offset) { NOTREACHED(); }
+
+void InProcessCommandBuffer::SetToken(int32 token) { NOTREACHED(); }
+
+void InProcessCommandBuffer::SetParseError(gpu::error::Error error) {
+  NOTREACHED();
+}
+
+void InProcessCommandBuffer::SetContextLostReason(
+    gpu::error::ContextLostReason reason) {
+  NOTREACHED();
+}
+
+namespace {
+
+static void PostCallback(const scoped_refptr<base::MessageLoopProxy>& loop,
+                         const base::Closure& callback) {
+  if (loop != base::MessageLoopProxy::current())
+    loop->PostTask(FROM_HERE, callback);
+  else
+    callback.Run();
+}
+
+static void RunCallback(scoped_ptr<base::Closure> callback) {
+  DCHECK(callback.get());
+  callback->Run();
+}
+
+}  // anonymous namespace
+
+base::Closure InProcessCommandBuffer::WrapCallback(
+    const base::Closure& callback) {
+  // Make sure the callback gets deleted on the target thread by passing
+  // ownership.
+  scoped_ptr<base::Closure> scoped_callback(new base::Closure(callback));
+  base::Closure callback_on_client_thread =
+      base::Bind(&RunCallback, base::Passed(&scoped_callback));
+  base::Closure wrapped_callback =
+      base::Bind(&PostCallback, base::MessageLoopProxy::current(),
+                 callback);
+  return wrapped_callback;
+}
+
+// static
+void InProcessCommandBuffer::EnableVirtualizedContext() {
+  g_use_virtualized_gl_context = true;
+}
+
+// static
+void InProcessCommandBuffer::SetScheduleCallback(
+    const base::Closure& callback) {
+  DCHECK(!g_uses_explicit_scheduling);
+  DCHECK(!SchedulerClientBase::HasClients());
+  g_uses_explicit_scheduling = true;
+  g_gpu_queue.Get().SetScheduleCallback(callback);
+}
+
+// static
+void InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread() {
+  g_gpu_queue.Get().RunTasks();
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
new file mode 100644
index 0000000..88d437d
--- /dev/null
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 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 GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/gpu_export.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gpu_preference.h"
+
+namespace gfx {
+class GLContext;
+class GLImage;
+class GLSurface;
+class Size;
+}
+
+namespace gpu {
+
+namespace gles2 {
+class GLES2Decoder;
+}
+
+class GpuScheduler;
+class TransferBufferManagerInterface;
+
+// This class provides a thread-safe interface to the global GPU service (for
+// example GPU thread) when being run in single process mode.
+// However, the behavior for accessing one context (i.e. one instance of this
+// class) from different client threads is undefined.
+class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer {
+ public:
+  InProcessCommandBuffer();
+  virtual ~InProcessCommandBuffer();
+
+  // Used to override the GPU thread with explicit scheduling.
+  // (By default an internal GPU thread will be spawned to handle all GL work
+  // and the two functions are unused.)
+  // The callback will be called from different client threads. After the
+  // callback is issued, the client is expected to eventually call
+  // ProcessGpuWorkOnCurrentThread(). The latter cannot be called from different
+  // threads.
+  // The callback needs to be set before any context is created.
+  static void SetScheduleCallback(const base::Closure& callback);
+  static void ProcessGpuWorkOnCurrentThread();
+
+  static void EnableVirtualizedContext();
+
+  bool Initialize(bool is_offscreen,
+                  bool share_resources,
+                  gfx::AcceleratedWidget window,
+                  const gfx::Size& size,
+                  const char* allowed_extensions,
+                  const std::vector<int32>& attribs,
+                  gfx::GpuPreference gpu_preference,
+                  const base::Closure& context_lost_callback,
+                  unsigned int share_group_id);
+  void Destroy();
+  void SignalSyncPoint(unsigned sync_point,
+                       const base::Closure& callback);
+  unsigned int CreateImageForGpuMemoryBuffer(
+      gfx::GpuMemoryBufferHandle buffer,
+      gfx::Size size);
+  void RemoveImage(unsigned int image_id);
+
+  // CommandBuffer implementation:
+  virtual bool Initialize() OVERRIDE;
+  virtual State GetState() OVERRIDE;
+  virtual State GetLastState() OVERRIDE;
+  virtual int32 GetLastToken() OVERRIDE;
+  virtual void Flush(int32 put_offset) OVERRIDE;
+  virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE;
+  virtual void SetGetBuffer(int32 shm_id) OVERRIDE;
+  virtual void SetGetOffset(int32 get_offset) OVERRIDE;
+  virtual gpu::Buffer CreateTransferBuffer(size_t size, int32* id) OVERRIDE;
+  virtual void DestroyTransferBuffer(int32 id) OVERRIDE;
+  virtual gpu::Buffer GetTransferBuffer(int32 id) OVERRIDE;
+  virtual void SetToken(int32 token) OVERRIDE;
+  virtual void SetParseError(gpu::error::Error error) OVERRIDE;
+  virtual void SetContextLostReason(
+      gpu::error::ContextLostReason reason) OVERRIDE;
+  virtual uint32 InsertSyncPoint() OVERRIDE;
+  virtual gpu::error::Error GetLastError() OVERRIDE;
+
+  // The serializer interface to the GPU service (i.e. thread).
+  class SchedulerClient {
+   public:
+     virtual ~SchedulerClient() {}
+     virtual void QueueTask(const base::Closure& task) = 0;
+  };
+
+ private:
+  bool InitializeOnGpuThread(bool is_offscreen,
+                             gfx::AcceleratedWidget window,
+                             const gfx::Size& size,
+                             const char* allowed_extensions,
+                             const std::vector<int32>& attribs,
+                             gfx::GpuPreference gpu_preference);
+  bool DestroyOnGpuThread();
+  void FlushOnGpuThread(int32 put_offset);
+  void CreateImageOnGpuThread(gfx::GpuMemoryBufferHandle buffer,
+                              gfx::Size size,
+                              unsigned int image_id);
+  void RemoveImageOnGpuThread(unsigned int image_id);
+  bool MakeCurrent();
+  bool IsContextLost();
+  base::Closure WrapCallback(const base::Closure& callback);
+  State GetStateFast();
+  void QueueTask(const base::Closure& task) { queue_->QueueTask(task); }
+
+  // Callbacks:
+  void OnContextLost();
+  void OnResizeView(gfx::Size size, float scale_factor);
+  bool GetBufferChanged(int32 transfer_buffer_id);
+  void PumpCommands();
+
+  // Members accessed on the gpu thread (possibly with the exception of
+  // creation):
+  bool context_lost_;
+  bool share_resources_;
+  scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+  scoped_ptr<GpuScheduler> gpu_scheduler_;
+  scoped_ptr<gles2::GLES2Decoder> decoder_;
+  scoped_refptr<gfx::GLContext> context_;
+  scoped_refptr<gfx::GLSurface> surface_;
+  base::Closure context_lost_callback_;
+  unsigned int share_group_id_;
+
+  // Members accessed on the client thread:
+  State last_state_;
+  int32 last_put_offset_;
+
+  // Accessed on both threads:
+  scoped_ptr<CommandBuffer> command_buffer_;
+  base::Lock command_buffer_lock_;
+  base::WaitableEvent flush_event_;
+  scoped_ptr<SchedulerClient> queue_;
+
+  DISALLOW_COPY_AND_ASSIGN(InProcessCommandBuffer);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index c47f15f..37d28a5 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -86,6 +86,8 @@
     'command_buffer/service/id_manager.cc',
     'command_buffer/service/image_manager.cc',
     'command_buffer/service/image_manager.h',
+    'command_buffer/service/in_process_command_buffer.cc',
+    'command_buffer/service/in_process_command_buffer.h',
     'command_buffer/service/logger.cc',
     'command_buffer/service/logger.h',
     'command_buffer/service/mailbox_manager.cc',
diff --git a/gpu/command_buffer_service.target.darwin-arm.mk b/gpu/command_buffer_service.target.darwin-arm.mk
index 8c6fdca..dc7f90e 100644
--- a/gpu/command_buffer_service.target.darwin-arm.mk
+++ b/gpu/command_buffer_service.target.darwin-arm.mk
@@ -53,6 +53,7 @@
 	gpu/command_buffer/service/gpu_tracer.cc \
 	gpu/command_buffer/service/id_manager.cc \
 	gpu/command_buffer/service/image_manager.cc \
+	gpu/command_buffer/service/in_process_command_buffer.cc \
 	gpu/command_buffer/service/logger.cc \
 	gpu/command_buffer/service/mailbox_manager.cc \
 	gpu/command_buffer/service/memory_program_cache.cc \
diff --git a/gpu/command_buffer_service.target.darwin-mips.mk b/gpu/command_buffer_service.target.darwin-mips.mk
index f324f40..8ab0fbf 100644
--- a/gpu/command_buffer_service.target.darwin-mips.mk
+++ b/gpu/command_buffer_service.target.darwin-mips.mk
@@ -53,6 +53,7 @@
 	gpu/command_buffer/service/gpu_tracer.cc \
 	gpu/command_buffer/service/id_manager.cc \
 	gpu/command_buffer/service/image_manager.cc \
+	gpu/command_buffer/service/in_process_command_buffer.cc \
 	gpu/command_buffer/service/logger.cc \
 	gpu/command_buffer/service/mailbox_manager.cc \
 	gpu/command_buffer/service/memory_program_cache.cc \
diff --git a/gpu/command_buffer_service.target.darwin-x86.mk b/gpu/command_buffer_service.target.darwin-x86.mk
index 4cef07b..6c7b408 100644
--- a/gpu/command_buffer_service.target.darwin-x86.mk
+++ b/gpu/command_buffer_service.target.darwin-x86.mk
@@ -53,6 +53,7 @@
 	gpu/command_buffer/service/gpu_tracer.cc \
 	gpu/command_buffer/service/id_manager.cc \
 	gpu/command_buffer/service/image_manager.cc \
+	gpu/command_buffer/service/in_process_command_buffer.cc \
 	gpu/command_buffer/service/logger.cc \
 	gpu/command_buffer/service/mailbox_manager.cc \
 	gpu/command_buffer/service/memory_program_cache.cc \
diff --git a/gpu/command_buffer_service.target.linux-arm.mk b/gpu/command_buffer_service.target.linux-arm.mk
index 8c6fdca..dc7f90e 100644
--- a/gpu/command_buffer_service.target.linux-arm.mk
+++ b/gpu/command_buffer_service.target.linux-arm.mk
@@ -53,6 +53,7 @@
 	gpu/command_buffer/service/gpu_tracer.cc \
 	gpu/command_buffer/service/id_manager.cc \
 	gpu/command_buffer/service/image_manager.cc \
+	gpu/command_buffer/service/in_process_command_buffer.cc \
 	gpu/command_buffer/service/logger.cc \
 	gpu/command_buffer/service/mailbox_manager.cc \
 	gpu/command_buffer/service/memory_program_cache.cc \
diff --git a/gpu/command_buffer_service.target.linux-mips.mk b/gpu/command_buffer_service.target.linux-mips.mk
index f324f40..8ab0fbf 100644
--- a/gpu/command_buffer_service.target.linux-mips.mk
+++ b/gpu/command_buffer_service.target.linux-mips.mk
@@ -53,6 +53,7 @@
 	gpu/command_buffer/service/gpu_tracer.cc \
 	gpu/command_buffer/service/id_manager.cc \
 	gpu/command_buffer/service/image_manager.cc \
+	gpu/command_buffer/service/in_process_command_buffer.cc \
 	gpu/command_buffer/service/logger.cc \
 	gpu/command_buffer/service/mailbox_manager.cc \
 	gpu/command_buffer/service/memory_program_cache.cc \
diff --git a/gpu/command_buffer_service.target.linux-x86.mk b/gpu/command_buffer_service.target.linux-x86.mk
index 4cef07b..6c7b408 100644
--- a/gpu/command_buffer_service.target.linux-x86.mk
+++ b/gpu/command_buffer_service.target.linux-x86.mk
@@ -53,6 +53,7 @@
 	gpu/command_buffer/service/gpu_tracer.cc \
 	gpu/command_buffer/service/id_manager.cc \
 	gpu/command_buffer/service/image_manager.cc \
+	gpu/command_buffer/service/in_process_command_buffer.cc \
 	gpu/command_buffer/service/logger.cc \
 	gpu/command_buffer/service/mailbox_manager.cc \
 	gpu/command_buffer/service/memory_program_cache.cc \
diff --git a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
index 7f5f170..57767ec 100644
--- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
+++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -1163,11 +1163,6 @@
   // Take ownership of the callback.
   context_->SignalSyncPoint(
       sync_point, base::Bind(&OnSignalSyncPoint, base::Owned(callback)));
-  // Make sure we have something to flush, or shallowFlushCHROMIUM()
-  // doesn't do anything.
-  gl_->helper()->Noop(1);
-  // This fill force PumpCommands() to run which is what triggers the signal.
-  shallowFlushCHROMIUM();
 }
 
 void WebGraphicsContext3DInProcessCommandBufferImpl::signalQuery(
@@ -1182,7 +1177,6 @@
     WGC3Denum current, WGC3Denum other) {
   gl_->LoseContextCHROMIUM(current, other);
   gl_->ShallowFlushCHROMIUM();
-  DCHECK(isContextLost());
 }
 
 DELEGATE_TO_GL_9(asyncTexImage2DCHROMIUM, AsyncTexImage2DCHROMIUM,