gpu: Refactor GpuMemoryBuffer framework for multi-process support.
    
This removes the ImageFactory interface and adjusts the buffer
allocation system for future multi-process support.

Also includes proper plumbing of internalformat to GLImage implementation
and makes sure the compositor is using the correct format.
    
TEST=gpu_unittests --gtest_filter=MockGpuMemoryBufferTest.Lifecycle
BUG=261649

Review URL: https://chromiumcodereview.appspot.com/20017005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@218034 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc
index 6344b1f..12288cd 100644
--- a/android_webview/lib/main/aw_main_delegate.cc
+++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -46,7 +46,7 @@
 bool AwMainDelegate::BasicStartupComplete(int* exit_code) {
   content::SetContentClient(&content_client_);
 
-  gpu::GLInProcessContext::SetGpuMemoryBufferFactory(
+  gpu::InProcessCommandBuffer::SetGpuMemoryBufferFactory(
       gpu_memory_buffer_factory_.get());
   gpu::InProcessCommandBuffer::EnableVirtualizedContext();
 
diff --git a/cc/resources/image_raster_worker_pool.cc b/cc/resources/image_raster_worker_pool.cc
index 408459c..7e524f6 100644
--- a/cc/resources/image_raster_worker_pool.cc
+++ b/cc/resources/image_raster_worker_pool.cc
@@ -156,6 +156,10 @@
       "state", TracedValue::FromValue(StateAsValue().release()));
 }
 
+GLenum ImageRasterWorkerPool::GetResourceFormat() const {
+  return GL_RGBA;  // Only format supported by CHROMIUM_map_image
+}
+
 void ImageRasterWorkerPool::OnRasterTasksFinished() {
   DCHECK(raster_tasks_pending_);
   raster_tasks_pending_ = false;
diff --git a/cc/resources/image_raster_worker_pool.h b/cc/resources/image_raster_worker_pool.h
index d4f4d74d..1816b27 100644
--- a/cc/resources/image_raster_worker_pool.h
+++ b/cc/resources/image_raster_worker_pool.h
@@ -21,6 +21,7 @@
 
   // Overridden from RasterWorkerPool:
   virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE;
+  virtual GLenum GetResourceFormat() const OVERRIDE;
   virtual void OnRasterTasksFinished() OVERRIDE;
   virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE;
 
diff --git a/cc/resources/pixel_buffer_raster_worker_pool.cc b/cc/resources/pixel_buffer_raster_worker_pool.cc
index a03ed81..7618803 100644
--- a/cc/resources/pixel_buffer_raster_worker_pool.cc
+++ b/cc/resources/pixel_buffer_raster_worker_pool.cc
@@ -236,6 +236,10 @@
       "state", TracedValue::FromValue(StateAsValue().release()));
 }
 
+GLenum PixelBufferRasterWorkerPool::GetResourceFormat() const {
+  return resource_provider()->best_texture_format();
+}
+
 void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
   TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::CheckForCompletedTasks");
 
diff --git a/cc/resources/pixel_buffer_raster_worker_pool.h b/cc/resources/pixel_buffer_raster_worker_pool.h
index d9613f7..9e966d3 100644
--- a/cc/resources/pixel_buffer_raster_worker_pool.h
+++ b/cc/resources/pixel_buffer_raster_worker_pool.h
@@ -29,6 +29,7 @@
 
   // Overridden from RasterWorkerPool:
   virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE;
+  virtual GLenum GetResourceFormat() const OVERRIDE;
   virtual void OnRasterTasksFinished() OVERRIDE;
   virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE;
 
diff --git a/cc/resources/raster_worker_pool.h b/cc/resources/raster_worker_pool.h
index d0e1e7c..8c4b493 100644
--- a/cc/resources/raster_worker_pool.h
+++ b/cc/resources/raster_worker_pool.h
@@ -13,6 +13,7 @@
 #include "cc/resources/raster_mode.h"
 #include "cc/resources/tile_priority.h"
 #include "cc/resources/worker_pool.h"
+#include "third_party/khronos/GLES2/gl2.h"
 
 class SkDevice;
 
@@ -183,6 +184,9 @@
   // even if they later get canceled by another call to ScheduleTasks().
   virtual void ScheduleTasks(RasterTask::Queue* queue) = 0;
 
+  // Returns the format that needs to be used for raster task resources.
+  virtual GLenum GetResourceFormat() const = 0;
+
   // TODO(vmpstr): Figure out an elegant way to not pass this many parameters.
   static RasterTask CreateRasterTask(
       const Resource* resource,
diff --git a/cc/resources/raster_worker_pool_perftest.cc b/cc/resources/raster_worker_pool_perftest.cc
index a4a258b..9215950 100644
--- a/cc/resources/raster_worker_pool_perftest.cc
+++ b/cc/resources/raster_worker_pool_perftest.cc
@@ -38,6 +38,10 @@
   virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE {
     NOTREACHED();
   }
+  virtual GLenum GetResourceFormat() const OVERRIDE {
+    NOTREACHED();
+    return GL_RGBA;
+  }
   virtual void OnRasterTasksFinished() OVERRIDE {
     NOTREACHED();
   }
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 0db1b4c..0296dd4b 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1350,6 +1350,7 @@
   resource->allocated = true;
   WebGraphicsContext3D* context3d = Context3d();
   DCHECK(context3d);
+  DCHECK_EQ(static_cast<GLenum>(GL_RGBA), resource->format);
   resource->image_id = context3d->createImageCHROMIUM(
       resource->size.width(), resource->size.height(), GL_RGBA8_OES);
   DCHECK(resource->image_id);
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index cff58830..c8d1e80 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -130,8 +130,7 @@
                       PixelBufferRasterWorkerPool::Create(
                           resource_provider, num_raster_threads),
                       num_raster_threads,
-                      rendering_stats_instrumentation,
-                      resource_provider->best_texture_format()));
+                      rendering_stats_instrumentation));
 }
 
 TileManager::TileManager(
@@ -139,8 +138,7 @@
     ResourceProvider* resource_provider,
     scoped_ptr<RasterWorkerPool> raster_worker_pool,
     size_t num_raster_threads,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation,
-    GLenum texture_format)
+    RenderingStatsInstrumentation* rendering_stats_instrumentation)
     : client_(client),
       resource_pool_(ResourcePool::Create(resource_provider)),
       raster_worker_pool_(raster_worker_pool.Pass()),
@@ -151,8 +149,7 @@
       resources_releasable_(0),
       ever_exceeded_memory_budget_(false),
       rendering_stats_instrumentation_(rendering_stats_instrumentation),
-      did_initialize_visible_tile_(false),
-      texture_format_(texture_format) {
+      did_initialize_visible_tile_(false) {
   raster_worker_pool_->SetClient(this);
 }
 
@@ -732,8 +729,9 @@
   ManagedTileState& mts = tile->managed_state();
 
   scoped_ptr<ResourcePool::Resource> resource =
-      resource_pool_->AcquireResource(tile->tile_size_.size(),
-                                      texture_format_);
+      resource_pool_->AcquireResource(
+          tile->tile_size_.size(),
+          raster_worker_pool_->GetResourceFormat());
   const Resource* const_resource = resource.get();
 
   // Create and queue all image decode tasks that this tile depends on.
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index 97c4f08..b76bc2f 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -103,8 +103,7 @@
               ResourceProvider* resource_provider,
               scoped_ptr<RasterWorkerPool> raster_worker_pool,
               size_t num_raster_threads,
-              RenderingStatsInstrumentation* rendering_stats_instrumentation,
-              GLenum texture_format);
+              RenderingStatsInstrumentation* rendering_stats_instrumentation);
 
   // Methods called by Tile
   friend class Tile;
@@ -176,8 +175,6 @@
 
   bool did_initialize_visible_tile_;
 
-  GLenum texture_format_;
-
   typedef base::hash_map<uint32_t, RasterWorkerPool::Task> PixelRefTaskMap;
   typedef base::hash_map<int, PixelRefTaskMap> LayerPixelRefTaskMap;
   LayerPixelRefTaskMap image_decode_tasks_;
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index 9e9e48a..c4f608bb 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -32,6 +32,7 @@
       completed_tasks_.pop_front();
     }
   }
+  virtual GLenum GetResourceFormat() const OVERRIDE { return GL_RGBA; }
   virtual void OnRasterTasksFinished() OVERRIDE {}
   virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE {}
 
@@ -47,8 +48,7 @@
                   NULL,
                   make_scoped_ptr<RasterWorkerPool>(new FakeRasterWorkerPool),
                   1,
-                  NULL,
-                  GL_RGBA) {}
+                  NULL) {}
 
 FakeTileManager::FakeTileManager(TileManagerClient* client,
                                  ResourceProvider* resource_provider)
@@ -56,8 +56,7 @@
                   resource_provider,
                   make_scoped_ptr<RasterWorkerPool>(new FakeRasterWorkerPool),
                   1,
-                  NULL,
-                  resource_provider->best_texture_format()) {}
+                  NULL) {}
 
 FakeTileManager::~FakeTileManager() {}
 
diff --git a/gpu/command_buffer/client/client_test_helper.cc b/gpu/command_buffer/client/client_test_helper.cc
index cccfa3b..31a91b2 100644
--- a/gpu/command_buffer/client/client_test_helper.cc
+++ b/gpu/command_buffer/client/client_test_helper.cc
@@ -151,6 +151,12 @@
           this, &MockCommandBufferBase::FlushHelper));
 }
 
+MockClientGpuControl::MockClientGpuControl() {
+}
+
+MockClientGpuControl::~MockClientGpuControl() {
+}
+
 }  // namespace gpu
 
 
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h
index 7010704..e9d6c36 100644
--- a/gpu/command_buffer/client/client_test_helper.h
+++ b/gpu/command_buffer/client/client_test_helper.h
@@ -11,6 +11,7 @@
 #include "gpu/command_buffer/common/cmd_buffer_common.h"
 #include "gpu/command_buffer/common/command_buffer.h"
 #include "gpu/command_buffer/common/compiler_specific.h"
+#include "gpu/command_buffer/common/gpu_control.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -81,6 +82,22 @@
   void DelegateToFake();
 };
 
+class MockClientGpuControl : public GpuControl {
+ public:
+  MockClientGpuControl();
+  virtual ~MockClientGpuControl();
+
+  MOCK_METHOD4(CreateGpuMemoryBuffer,
+               gfx::GpuMemoryBuffer*(size_t width,
+                                     size_t height,
+                                     unsigned internalformat,
+                                     int32* id));
+  MOCK_METHOD1(DestroyGpuMemoryBuffer, void(int32 id));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockClientGpuControl);
+};
+
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_CLIENT_CLIENT_TEST_HELPER_H_
diff --git a/gpu/command_buffer/client/gl_in_process_context.cc b/gpu/command_buffer/client/gl_in_process_context.cc
index cdbfc9f..f778047 100644
--- a/gpu/command_buffer/client/gl_in_process_context.cc
+++ b/gpu/command_buffer/client/gl_in_process_context.cc
@@ -23,8 +23,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "gpu/command_buffer/client/gles2_implementation.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"
@@ -43,11 +41,8 @@
 const size_t kMinTransferBufferSize = 1 * 256 * 1024;
 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
 
-static GpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL;
-
 class GLInProcessContextImpl
     : public GLInProcessContext,
-      public gles2::ImageFactory,
       public base::SupportsWeakPtr<GLInProcessContextImpl> {
  public:
   explicit GLInProcessContextImpl();
@@ -70,12 +65,6 @@
       OVERRIDE;
   virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE;
 
-  // ImageFactory implementation:
-  virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-      int width, int height, GLenum internalformat,
-      unsigned* image_id) OVERRIDE;
-  virtual void DeleteGpuMemoryBuffer(unsigned image_id) OVERRIDE;
-
  private:
   void Destroy();
   void PollQueryCallbacks();
@@ -108,24 +97,6 @@
   return g_all_shared_contexts.Get().size();
 }
 
-scoped_ptr<gfx::GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer(
-    int width, int height, GLenum internalformat, unsigned int* image_id) {
-  scoped_ptr<gfx::GpuMemoryBuffer> buffer(
-      g_gpu_memory_buffer_factory->CreateGpuMemoryBuffer(width,
-                                                         height,
-                                                         internalformat));
-  if (!buffer)
-    return scoped_ptr<gfx::GpuMemoryBuffer>();
-
-  *image_id = command_buffer_->CreateImageForGpuMemoryBuffer(
-      buffer->GetHandle(), gfx::Size(width, height));
-  return buffer.Pass();
-}
-
-void GLInProcessContextImpl::DeleteGpuMemoryBuffer(unsigned int image_id) {
-  command_buffer_->RemoveImage(image_id);
-}
-
 GLInProcessContextImpl::GLInProcessContextImpl()
     : share_group_id_(0), context_lost_(false) {}
 
@@ -279,7 +250,7 @@
       share_group,
       transfer_buffer_.get(),
       false,
-      this));
+      command_buffer_.get()));
 
   if (share_resources) {
     g_all_shared_contexts.Get().insert(this);
@@ -421,11 +392,4 @@
   return context.release();
 }
 
-// static
-void GLInProcessContext::SetGpuMemoryBufferFactory(
-    GpuMemoryBufferFactory* factory) {
-  DCHECK_EQ(0u, SharedContextCount());
-  g_gpu_memory_buffer_factory = factory;
-}
-
 }  // 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 09f8140..7e924b5 100644
--- a/gpu/command_buffer/client/gl_in_process_context.h
+++ b/gpu/command_buffer/client/gl_in_process_context.h
@@ -22,8 +22,6 @@
 class GLES2Implementation;
 }
 
-class GpuMemoryBufferFactory;
-
 // The default uninitialized value is -1.
 struct GLES2_IMPL_EXPORT GLInProcessContextAttribs {
   GLInProcessContextAttribs();
@@ -42,9 +40,6 @@
  public:
   virtual ~GLInProcessContext() {}
 
-  // Must be called before any GLInProcessContext instances are created.
-  static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory);
-
   // Create a GLInProcessContext, if |is_offscreen| is true, renders to an
   // offscreen context. |attrib_list| must be NULL or a NONE-terminated list
   // of attribute/value pairs.
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 9285b6d8..5a223b4d 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -86,7 +86,7 @@
       ShareGroup* share_group,
       TransferBufferInterface* transfer_buffer,
       bool bind_generates_resource,
-      ImageFactory* image_factory)
+      GpuControl* gpu_control)
     : helper_(helper),
       transfer_buffer_(transfer_buffer),
       angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
@@ -111,7 +111,7 @@
       use_count_(0),
       current_query_(NULL),
       error_message_callback_(NULL),
-      image_factory_(image_factory) {
+      gpu_control_(gpu_control) {
   GPU_DCHECK(helper);
   GPU_DCHECK(transfer_buffer);
 
@@ -165,7 +165,7 @@
 
   query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
   buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
-  gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(image_factory_));
+  gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
 
 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
   GetIdHandler(id_namespaces::kBuffers)->MakeIds(
@@ -2089,7 +2089,7 @@
             "GL_CHROMIUM_map_sub "
             "GL_CHROMIUM_shallow_flush "
             "GL_EXT_unpack_subimage";
-        if (image_factory_ != NULL) {
+        if (gpu_control_ != NULL) {
           // The first space character is intentional.
           str += " GL_CHROMIUM_map_image";
         }
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index c2bf49f4..bacb582e 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -20,7 +20,6 @@
 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
-#include "gpu/command_buffer/client/image_factory.h"
 #include "gpu/command_buffer/client/query_tracker.h"
 #include "gpu/command_buffer/client/ref_counted.h"
 #include "gpu/command_buffer/client/ring_buffer.h"
@@ -98,6 +97,7 @@
 
 namespace gpu {
 
+class GpuControl;
 class MappedMemoryManager;
 class ScopedTransferBufferPtr;
 class TransferBufferInterface;
@@ -177,7 +177,7 @@
       ShareGroup* share_group,
       TransferBufferInterface* transfer_buffer,
       bool bind_generates_resource,
-      ImageFactory* image_factory);
+      GpuControl* gpu_control);
 
   virtual ~GLES2Implementation();
 
@@ -668,7 +668,7 @@
 
   scoped_ptr<std::string> current_trace_name_;
 
-  ImageFactory* image_factory_;
+  GpuControl* gpu_control_;
 
   DISALLOW_COPY_AND_ASSIGN(GLES2Implementation);
 };
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index e58907c..0289547b 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -366,6 +366,8 @@
     helper_.reset(new GLES2CmdHelper(command_buffer()));
     helper_->Initialize(kCommandBufferSizeBytes);
 
+    gpu_control_.reset(new StrictMock<MockClientGpuControl>());
+
     GLES2Implementation::GLStaticState state;
     GLES2Implementation::GLStaticState::IntState& int_state = state.int_state;
     int_state.max_combined_texture_image_units = kMaxCombinedTextureImageUnits;
@@ -401,7 +403,7 @@
           NULL,
           transfer_buffer_.get(),
           bind_generates_resource,
-          NULL));
+          gpu_control_.get()));
       ASSERT_TRUE(gl_->Initialize(
           kTransferBufferSize,
           kTransferBufferSize,
@@ -473,6 +475,7 @@
 
   Sequence sequence_;
   scoped_ptr<MockClientCommandBuffer> command_buffer_;
+  scoped_ptr<MockClientGpuControl> gpu_control_;
   scoped_ptr<GLES2CmdHelper> helper_;
   scoped_ptr<MockTransferBuffer> transfer_buffer_;
   scoped_ptr<GLES2Implementation> gl_;
@@ -2476,7 +2479,8 @@
       "GL_CHROMIUM_flipy "
       "GL_CHROMIUM_map_sub "
       "GL_CHROMIUM_shallow_flush "
-      "GL_EXT_unpack_subimage";
+      "GL_EXT_unpack_subimage "
+      "GL_CHROMIUM_map_image";
   const char kBad = 0x12;
   struct Cmds {
     cmd::SetBucketSize set_bucket_size1;
diff --git a/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc b/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
index c1c9b4d..a957cc4 100644
--- a/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
+++ b/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
@@ -6,15 +6,13 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/image_factory.h"
-#include "ui/gfx/gpu_memory_buffer.h"
+#include "gpu/command_buffer/common/gpu_control.h"
 
 namespace gpu {
 namespace gles2 {
 
-GpuMemoryBufferTracker::GpuMemoryBufferTracker(ImageFactory* factory)
-    : buffers_(),
-      factory_(factory) {
+GpuMemoryBufferTracker::GpuMemoryBufferTracker(GpuControl* gpu_control)
+    : gpu_control_(gpu_control) {
 }
 
 GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
@@ -23,37 +21,33 @@
   }
 }
 
-GLuint GpuMemoryBufferTracker::CreateBuffer(
-    GLsizei width, GLsizei height, GLenum internalformat) {
-  GLuint image_id = 0;
-  DCHECK(factory_);
-  scoped_ptr<gfx::GpuMemoryBuffer> buffer =
-      factory_->CreateGpuMemoryBuffer(width, height, internalformat, &image_id);
-
-  if (buffer.get() == NULL)
+int32 GpuMemoryBufferTracker::CreateBuffer(
+    size_t width, size_t height, int32 internalformat) {
+  int32 image_id = 0;
+  DCHECK(gpu_control_);
+  gfx::GpuMemoryBuffer* buffer = gpu_control_->CreateGpuMemoryBuffer(
+      width, height, internalformat, &image_id);
+  if (!buffer)
     return 0;
 
   std::pair<BufferMap::iterator, bool> result =
-      buffers_.insert(std::make_pair(image_id, buffer.release()));
+      buffers_.insert(std::make_pair(image_id, buffer));
   GPU_DCHECK(result.second);
 
   return image_id;
 }
 
-gfx::GpuMemoryBuffer* GpuMemoryBufferTracker::GetBuffer(GLuint image_id) {
+gfx::GpuMemoryBuffer* GpuMemoryBufferTracker::GetBuffer(int32 image_id) {
   BufferMap::iterator it = buffers_.find(image_id);
   return (it != buffers_.end()) ? it->second : NULL;
 }
 
-void GpuMemoryBufferTracker::RemoveBuffer(GLuint image_id) {
+void GpuMemoryBufferTracker::RemoveBuffer(int32 image_id) {
   BufferMap::iterator buffer_it = buffers_.find(image_id);
-  if (buffer_it != buffers_.end()) {
-    gfx::GpuMemoryBuffer* buffer = buffer_it->second;
+  if (buffer_it != buffers_.end())
     buffers_.erase(buffer_it);
-    delete buffer;
-  }
-  DCHECK(factory_);
-  factory_->DeleteGpuMemoryBuffer(image_id);
+  DCHECK(gpu_control_);
+  gpu_control_->DestroyGpuMemoryBuffer(image_id);
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/client/gpu_memory_buffer_tracker.h b/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
index 1192b17..0b07dd0a1 100644
--- a/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
+++ b/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
@@ -5,8 +5,6 @@
 #ifndef GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
 #define GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
 
-#include <GLES2/gl2.h>
-
 #include "base/basictypes.h"
 #include "gles2_impl_export.h"
 #include "gpu/command_buffer/client/hash_tables.h"
@@ -16,25 +14,24 @@
 }
 
 namespace gpu {
+class GpuControl;
+
 namespace gles2 {
-class ImageFactory;
 
 // Tracks GPU memory buffer objects on the client side.
 class GLES2_IMPL_EXPORT GpuMemoryBufferTracker {
  public:
-  // Ownership of |factory| remains with caller.
-  explicit GpuMemoryBufferTracker(ImageFactory* factory);
+  explicit GpuMemoryBufferTracker(GpuControl* gpu_control);
   virtual ~GpuMemoryBufferTracker();
 
-  GLuint CreateBuffer(
-      GLsizei width, GLsizei height, GLenum internalformat);
-  gfx::GpuMemoryBuffer* GetBuffer(GLuint image_id);
-  void RemoveBuffer(GLuint image_id);
+  int32 CreateBuffer(size_t width, size_t height, int32 internalformat);
+  gfx::GpuMemoryBuffer* GetBuffer(int32 image_id);
+  void RemoveBuffer(int32 image_id);
 
  private:
-  typedef gpu::hash_map<GLuint, gfx::GpuMemoryBuffer*> BufferMap;
+  typedef gpu::hash_map<int32, gfx::GpuMemoryBuffer*> BufferMap;
   BufferMap buffers_;
-  ImageFactory* factory_;
+  GpuControl* gpu_control_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferTracker);
 };
diff --git a/gpu/command_buffer/client/image_factory.h b/gpu/command_buffer/client/image_factory.h
deleted file mode 100644
index 449c8a4..0000000
--- a/gpu/command_buffer/client/image_factory.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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 GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
-#define GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
-
-#include <GLES2/gl2.h>
-
-#include "base/memory/scoped_ptr.h"
-#include "gles2_impl_export.h"
-
-namespace gfx {
-class GpuMemoryBuffer;
-}
-
-namespace gpu {
-namespace gles2 {
-
-class GLES2_IMPL_EXPORT ImageFactory {
-
- public:
-  virtual ~ImageFactory() {}
-
-  // Create a GpuMemoryBuffer and makes it available to the
-  // service side by inserting it to the ImageManager.
-  virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-      int width, int height, GLenum internalformat, unsigned* image_id) = 0;
-  virtual void DeleteGpuMemoryBuffer(unsigned image_id) = 0;
-};
-
-}  // namespace gles2
-}  // namespace gpu
-
-#endif  // GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index 37c7a53..76bb3fe 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -56,7 +56,6 @@
   kTextures,
   kQueries,
   kVertexArrays,
-  kImages,
   kNumIdNamespaces
 };
 
diff --git a/gpu/command_buffer/common/gpu_control.h b/gpu/command_buffer/common/gpu_control.h
new file mode 100644
index 0000000..5534ca78
--- /dev/null
+++ b/gpu/command_buffer/common/gpu_control.h
@@ -0,0 +1,39 @@
+// 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 GPU_COMMAND_BUFFER_COMMON_GPU_CONTROL_H_
+#define GPU_COMMAND_BUFFER_COMMON_GPU_CONTROL_H_
+
+#include "gpu/gpu_export.h"
+
+namespace gfx {
+class GpuMemoryBuffer;
+}
+
+namespace gpu {
+
+// Common interface for GpuControl implementations.
+class GPU_EXPORT GpuControl {
+ public:
+  GpuControl() {}
+  virtual ~GpuControl() {}
+
+  // Create a gpu memory buffer of the given dimensions and format. Returns
+  // its ID or -1 on error.
+  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat,
+      int32* id) = 0;
+
+  // Destroy a gpu memory buffer. The ID must be positive.
+  virtual void DestroyGpuMemoryBuffer(int32 id) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GpuControl);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_COMMON_GPU_CONTROL_H_
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 0cf991a..90932fb 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -67,7 +67,6 @@
   id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator);
   id_namespaces_[id_namespaces::kQueries].reset(new IdAllocator);
   id_namespaces_[id_namespaces::kVertexArrays].reset(new IdAllocator);
-  id_namespaces_[id_namespaces::kImages].reset(new IdAllocator);
 }
 
 static void GetIntegerv(GLenum pname, uint32* var) {
diff --git a/gpu/command_buffer/service/gpu_control_service.cc b/gpu/command_buffer/service/gpu_control_service.cc
new file mode 100644
index 0000000..d368ff92
--- /dev/null
+++ b/gpu/command_buffer/service/gpu_control_service.cc
@@ -0,0 +1,74 @@
+// 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 "gpu/command_buffer/service/gpu_control_service.h"
+
+#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/service/gpu_memory_buffer_manager.h"
+
+namespace gpu {
+
+GpuControlService::GpuControlService(
+    GpuMemoryBufferManagerInterface* gpu_memory_buffer_manager,
+    GpuMemoryBufferFactory* gpu_memory_buffer_factory)
+    : gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+      gpu_memory_buffer_factory_(gpu_memory_buffer_factory) {
+}
+
+GpuControlService::~GpuControlService() {
+}
+
+gfx::GpuMemoryBuffer* GpuControlService::CreateGpuMemoryBuffer(
+    size_t width,
+    size_t height,
+    unsigned internalformat,
+    int32* id) {
+  *id = -1;
+
+  CHECK(gpu_memory_buffer_factory_) << "No GPU memory buffer factory provided";
+  linked_ptr<gfx::GpuMemoryBuffer> buffer = make_linked_ptr(
+      gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(width,
+                                                        height,
+                                                        internalformat));
+  if (!buffer.get())
+    return NULL;
+
+  static int32 next_id = 1;
+  *id = next_id++;
+
+  if (!RegisterGpuMemoryBuffer(*id,
+                               buffer->GetHandle(),
+                               width,
+                               height,
+                               internalformat)) {
+    *id = -1;
+    return NULL;
+  }
+
+  gpu_memory_buffers_[*id] = buffer;
+  return buffer.get();
+}
+
+void GpuControlService::DestroyGpuMemoryBuffer(int32 id) {
+  GpuMemoryBufferMap::iterator it = gpu_memory_buffers_.find(id);
+  if (it != gpu_memory_buffers_.end())
+    gpu_memory_buffers_.erase(it);
+
+  gpu_memory_buffer_manager_->DestroyGpuMemoryBuffer(id);
+}
+
+bool GpuControlService::RegisterGpuMemoryBuffer(
+    int32 id,
+    gfx::GpuMemoryBufferHandle buffer,
+    size_t width,
+    size_t height,
+    unsigned internalformat) {
+  return gpu_memory_buffer_manager_->RegisterGpuMemoryBuffer(id,
+                                                             buffer,
+                                                             width,
+                                                             height,
+                                                             internalformat);
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_control_service.h b/gpu/command_buffer/service/gpu_control_service.h
new file mode 100644
index 0000000..a12fee46
--- /dev/null
+++ b/gpu/command_buffer/service/gpu_control_service.h
@@ -0,0 +1,51 @@
+// 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 GPU_COMMAND_BUFFER_SERVICE_GPU_CONTROL_SERVICE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_CONTROL_SERVICE_H_
+
+#include <map>
+
+#include "base/memory/linked_ptr.h"
+#include "gpu/command_buffer/common/gpu_control.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace gpu {
+class GpuMemoryBufferFactory;
+class GpuMemoryBufferManagerInterface;
+
+class GPU_EXPORT GpuControlService : public GpuControl {
+ public:
+  GpuControlService(GpuMemoryBufferManagerInterface* gpu_memory_buffer_manager,
+                    GpuMemoryBufferFactory* gpu_memory_buffer_factory);
+  virtual ~GpuControlService();
+
+  // Overridden from GpuControl:
+  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat,
+      int32* id) OVERRIDE;
+  virtual void DestroyGpuMemoryBuffer(int32 id) OVERRIDE;
+
+  // Register an existing gpu memory buffer and get an ID that can be used
+  // to identify it in the command buffer.
+  bool RegisterGpuMemoryBuffer(int32 id,
+                               gfx::GpuMemoryBufferHandle buffer,
+                               size_t width,
+                               size_t height,
+                               unsigned internalformat);
+
+ private:
+  GpuMemoryBufferManagerInterface* gpu_memory_buffer_manager_;
+  GpuMemoryBufferFactory* gpu_memory_buffer_factory_;
+  typedef std::map<int32, linked_ptr<gfx::GpuMemoryBuffer> > GpuMemoryBufferMap;
+  GpuMemoryBufferMap gpu_memory_buffers_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuControlService);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GPU_CONTROL_SERVICE_H_
diff --git a/gpu/command_buffer/service/gpu_memory_buffer_manager.h b/gpu/command_buffer/service/gpu_memory_buffer_manager.h
new file mode 100644
index 0000000..fb44ede
--- /dev/null
+++ b/gpu/command_buffer/service/gpu_memory_buffer_manager.h
@@ -0,0 +1,28 @@
+// 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 GPU_COMMAND_BUFFER_SERVICE_GPU_MEMORY_BUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_MEMORY_BUFFER_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "gpu/gpu_export.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace gpu {
+
+class GPU_EXPORT GpuMemoryBufferManagerInterface {
+ public:
+  virtual ~GpuMemoryBufferManagerInterface() {}
+
+  virtual bool RegisterGpuMemoryBuffer(int32 id,
+                                       gfx::GpuMemoryBufferHandle buffer,
+                                       size_t width,
+                                       size_t height,
+                                       unsigned internalformat) = 0;
+  virtual void DestroyGpuMemoryBuffer(int32 id) = 0;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/gpu/command_buffer/service/image_manager.cc b/gpu/command_buffer/service/image_manager.cc
index 6be4e66..a09af15 100644
--- a/gpu/command_buffer/service/image_manager.cc
+++ b/gpu/command_buffer/service/image_manager.cc
@@ -15,6 +15,36 @@
 ImageManager::~ImageManager() {
 }
 
+bool ImageManager::RegisterGpuMemoryBuffer(int32 id,
+                                           gfx::GpuMemoryBufferHandle buffer,
+                                           size_t width,
+                                           size_t height,
+                                           unsigned internalformat) {
+  if (id <= 0) {
+    DVLOG(0) << "Cannot register GPU memory buffer with non-positive ID.";
+    return false;
+  }
+
+  if (LookupImage(id)) {
+    DVLOG(0) << "GPU memory buffer ID already in use.";
+    return false;
+  }
+
+  scoped_refptr<gfx::GLImage> gl_image =
+      gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer,
+                                                    gfx::Size(width, height),
+                                                    internalformat);
+  if (!gl_image)
+    return false;
+
+  AddImage(gl_image.get(), id);
+  return true;
+}
+
+void ImageManager::DestroyGpuMemoryBuffer(int32 id) {
+  RemoveImage(id);
+}
+
 void ImageManager::AddImage(gfx::GLImage* image, int32 service_id) {
   gl_images_[service_id] = image;
 }
diff --git a/gpu/command_buffer/service/image_manager.h b/gpu/command_buffer/service/image_manager.h
index 1b42146..a125ae80 100644
--- a/gpu/command_buffer/service/image_manager.h
+++ b/gpu/command_buffer/service/image_manager.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/containers/hash_tables.h"
 #include "base/memory/ref_counted.h"
+#include "gpu/command_buffer/service/gpu_memory_buffer_manager.h"
 #include "gpu/gpu_export.h"
 
 namespace gfx {
@@ -18,10 +19,20 @@
 namespace gles2 {
 
 // Interface used by the cmd decoder to lookup images.
-class GPU_EXPORT ImageManager : public base::RefCounted<ImageManager> {
+class GPU_EXPORT ImageManager
+    : public GpuMemoryBufferManagerInterface,
+      public base::RefCounted<ImageManager> {
  public:
   ImageManager();
 
+  // Overridden from GpuMemoryBufferManagerInterface:
+  virtual bool RegisterGpuMemoryBuffer(int32 id,
+                                       gfx::GpuMemoryBufferHandle buffer,
+                                       size_t width,
+                                       size_t height,
+                                       unsigned internalformat) OVERRIDE;
+  virtual void DestroyGpuMemoryBuffer(int32 id) OVERRIDE;
+
   void AddImage(gfx::GLImage* gl_image, int32 service_id);
   void RemoveImage(int32 service_id);
   gfx::GLImage* LookupImage(int32 service_id);
@@ -29,7 +40,7 @@
  private:
   friend class base::RefCounted<ImageManager>;
 
-  ~ImageManager();
+  virtual ~ImageManager();
 
   typedef base::hash_map<uint32, scoped_refptr<gfx::GLImage> > GLImageMap;
   GLImageMap gl_images_;
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index ccbfb32..2f949c9 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -22,10 +22,10 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/sequence_checker.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_control_service.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"
@@ -43,6 +43,7 @@
 
 static bool g_use_virtualized_gl_context = false;
 static bool g_uses_explicit_scheduling = false;
+static GpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL;
 
 template <typename T>
 static void RunTaskWithResult(base::Callback<T(void)> task,
@@ -390,6 +391,10 @@
       &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
   command_buffer_ = command_buffer.Pass();
 
+  gpu_control_.reset(
+      new GpuControlService(decoder_->GetContextGroup()->image_manager(),
+                            g_gpu_memory_buffer_factory));
+
   decoder_->set_engine(gpu_scheduler_.get());
 
   if (!surface_) {
@@ -496,55 +501,6 @@
          sequence_checker_->CalledOnValidSequencedThread());
 }
 
-unsigned int InProcessCommandBuffer::CreateImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer,
-    gfx::Size size) {
-  CheckSequencedThread();
-  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) {
-  CheckSequencedThread();
-  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) {
-  CheckSequencedThread();
-  {
-    // 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) {
-  CheckSequencedThread();
-  decoder_->GetContextGroup()->image_manager()->RemoveImage(image_id);
-}
-
 void InProcessCommandBuffer::OnContextLost() {
   CheckSequencedThread();
   if (!context_lost_callback_.is_null()) {
@@ -680,6 +636,28 @@
   QueueTask(WrapCallback(callback));
 }
 
+gfx::GpuMemoryBuffer* InProcessCommandBuffer::CreateGpuMemoryBuffer(
+    size_t width,
+    size_t height,
+    unsigned internalformat,
+    int32* id) {
+  CheckSequencedThread();
+  base::AutoLock lock(command_buffer_lock_);
+  return gpu_control_->CreateGpuMemoryBuffer(width,
+                                             height,
+                                             internalformat,
+                                             id);
+}
+
+void InProcessCommandBuffer::DestroyGpuMemoryBuffer(int32 id) {
+  CheckSequencedThread();
+  base::Closure task = base::Bind(&GpuControl::DestroyGpuMemoryBuffer,
+                                  base::Unretained(gpu_control_.get()),
+                                  id);
+
+  QueueTask(task);
+}
+
 gpu::error::Error InProcessCommandBuffer::GetLastError() {
   CheckSequencedThread();
   return last_state_.error;
@@ -753,4 +731,10 @@
   g_gpu_queue.Get().RunTasks();
 }
 
+// static
+void InProcessCommandBuffer::SetGpuMemoryBufferFactory(
+    GpuMemoryBufferFactory* factory) {
+  g_gpu_memory_buffer_factory = factory;
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index 9bdbd49..03c0f42 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -14,6 +14,7 @@
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/gpu_control.h"
 #include "gpu/gpu_export.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_widget_types.h"
@@ -26,7 +27,6 @@
 
 namespace gfx {
 class GLContext;
-class GLImage;
 class GLSurface;
 class Size;
 }
@@ -37,6 +37,7 @@
 class GLES2Decoder;
 }
 
+class GpuMemoryBufferFactory;
 class GpuScheduler;
 class TransferBufferManagerInterface;
 
@@ -44,7 +45,8 @@
 // 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 {
+class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer,
+                                          public GpuControl {
  public:
   InProcessCommandBuffer();
   virtual ~InProcessCommandBuffer();
@@ -61,6 +63,7 @@
   static void ProcessGpuWorkOnCurrentThread();
 
   static void EnableVirtualizedContext();
+  static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory);
 
   // If |surface| is not NULL, use it directly; in this case, the command
   // buffer gpu thread must be the same as the client thread. Otherwise create
@@ -78,10 +81,6 @@
   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;
@@ -102,6 +101,14 @@
   virtual uint32 InsertSyncPoint() OVERRIDE;
   virtual gpu::error::Error GetLastError() OVERRIDE;
 
+  // GpuControl implementation:
+  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat,
+      int32* id) OVERRIDE;
+  virtual void DestroyGpuMemoryBuffer(int32 id) OVERRIDE;
+
   // The serializer interface to the GPU service (i.e. thread).
   class SchedulerClient {
    public:
@@ -118,10 +125,6 @@
                              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);
@@ -158,6 +161,7 @@
   scoped_ptr<SchedulerClient> queue_;
   State state_after_last_flush_;
   base::Lock state_after_last_flush_lock_;
+  scoped_ptr<GpuControl> gpu_control_;
 
   // Only used with explicit scheduling and the gpu thread is the same as
   // the client thread.
diff --git a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittests.cc b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittests.cc
index 9c9d5ab..91fbc6ae 100644
--- a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittests.cc
+++ b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittests.cc
@@ -11,6 +11,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/process/process_handle.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/tests/gl_manager.h"
 #include "gpu/command_buffer/tests/gl_test_utils.h"
@@ -51,24 +53,16 @@
   DISALLOW_COPY_AND_ASSIGN(MockGpuMemoryBuffer);
 };
 
-class MockImageFactory : public ImageFactory {
+class MockGpuMemoryBufferFactory : public GpuMemoryBufferFactory {
  public:
-  MockImageFactory(ImageManager* image_manager) {}
-  virtual ~MockImageFactory() {}
+  MockGpuMemoryBufferFactory() {}
+  virtual ~MockGpuMemoryBufferFactory() {}
 
-  MOCK_METHOD4(CreateGpuMemoryBufferMock, gfx::GpuMemoryBuffer*(
-      int width, int height, GLenum internalformat, unsigned* image_id));
-  MOCK_METHOD1(DeleteGpuMemoryBuffer, void(unsigned));
-  // Workaround for mocking methods that return scoped_ptrs
-  virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-      int width, int height, GLenum internalformat,
-      unsigned* image_id) OVERRIDE {
-    return scoped_ptr<gfx::GpuMemoryBuffer>(CreateGpuMemoryBufferMock(
-        width, height, internalformat, image_id));
-  }
+  MOCK_METHOD3(CreateGpuMemoryBuffer,
+               gfx::GpuMemoryBuffer*(size_t, size_t, unsigned));
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(MockImageFactory);
+  DISALLOW_COPY_AND_ASSIGN(MockGpuMemoryBufferFactory);
 };
 
 class MockGpuMemoryBufferTest : public testing::Test {
@@ -76,10 +70,9 @@
   virtual void SetUp() {
     GLManager::Options options;
     image_manager_ = new ImageManager;
-    image_factory_.reset(
-        new StrictMock<MockImageFactory>(image_manager_.get()));
+    gpu_memory_buffer_factory_.reset(new MockGpuMemoryBufferFactory);
     options.image_manager = image_manager_.get();
-    options.image_factory = image_factory_.get();
+    options.gpu_memory_buffer_factory = gpu_memory_buffer_factory_.get();
 
     gl_.Initialize(options);
     gl_.MakeCurrent();
@@ -108,8 +101,8 @@
     gl_.Destroy();
   }
 
-  scoped_ptr<StrictMock<MockImageFactory> > image_factory_;
   scoped_refptr<ImageManager> image_manager_;
+  scoped_ptr<MockGpuMemoryBufferFactory> gpu_memory_buffer_factory_;
   GLManager gl_;
   GLuint texture_ids_[2];
   GLuint framebuffer_id_;
@@ -133,29 +126,21 @@
   handle.type = gfx::SHARED_MEMORY_BUFFER;
   handle.handle = duped_shared_memory_handle;
 
-  const GLuint kImageId = 345u;
-
-  EXPECT_CALL(*image_factory_.get(), CreateGpuMemoryBufferMock(
-      kImageWidth, kImageHeight, GL_RGBA8_OES, _))
+  EXPECT_CALL(*gpu_memory_buffer_factory_.get(), CreateGpuMemoryBuffer(
+      kImageWidth, kImageHeight, GL_RGBA8_OES))
       .Times(1)
-      .WillOnce(DoAll(SetArgPointee<3>(kImageId), Return(gpu_memory_buffer)))
+      .WillOnce(Return(gpu_memory_buffer))
       .RetiresOnSaturation();
-
-  // Create the GLImage and insert it into the ImageManager, which
-  // would be done within CreateGpuMemoryBufferMock if it weren't a mock.
-  GLuint image_id = glCreateImageCHROMIUM(
-      kImageWidth, kImageHeight, GL_RGBA8_OES);
-  EXPECT_EQ(kImageId, image_id);
-
   EXPECT_CALL(*gpu_memory_buffer, GetHandle())
+      .Times(1)
       .WillOnce(Return(handle))
       .RetiresOnSaturation();
 
-  gfx::Size size(kImageWidth, kImageHeight);
-  scoped_refptr<gfx::GLImage> gl_image(
-      gfx::GLImage::CreateGLImageForGpuMemoryBuffer(
-          gpu_memory_buffer->GetHandle(), size));
-  image_manager_->AddImage(gl_image.get(), image_id);
+  // Create the image. This should add the image ID to the ImageManager.
+  GLuint image_id = glCreateImageCHROMIUM(
+      kImageWidth, kImageHeight, GL_RGBA8_OES);
+  EXPECT_NE(0u, image_id);
+  EXPECT_TRUE(image_manager_->LookupImage(image_id) != NULL);
 
   EXPECT_CALL(*gpu_memory_buffer, IsMapped())
       .WillOnce(Return(false))
@@ -217,11 +202,6 @@
   EXPECT_CALL(*gpu_memory_buffer, Die())
       .Times(1)
       .RetiresOnSaturation();
-
-  EXPECT_CALL(*image_factory_.get(), DeleteGpuMemoryBuffer(image_id))
-      .Times(1)
-      .RetiresOnSaturation();
-
   glDestroyImageCHROMIUM(image_id);
 }
 
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 54ff645..2c48164 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -17,6 +17,7 @@
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/gl_context_virtual.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gpu_control_service.h"
 #include "gpu/command_buffer/service/gpu_scheduler.h"
 #include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
@@ -39,8 +40,7 @@
       virtual_manager(NULL),
       bind_generates_resource(false),
       context_lost_allowed(false),
-      image_manager(NULL),
-      image_factory(NULL) {
+      image_manager(NULL) {
 }
 
 GLManager::GLManager()
@@ -132,6 +132,10 @@
   ASSERT_TRUE(command_buffer_->Initialize())
       << "could not create command buffer service";
 
+  gpu_control_.reset(
+      new GpuControlService(decoder_->GetContextGroup()->image_manager(),
+                            options.gpu_memory_buffer_factory));
+
   gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(),
                                         decoder_.get(),
                                         decoder_.get()));
@@ -189,7 +193,7 @@
       client_share_group,
       transfer_buffer_.get(),
       options.bind_generates_resource,
-      options.image_factory));
+      gpu_control_.get()));
 
   ASSERT_TRUE(gles2_implementation_->Initialize(
       kStartTransferBufferSize,
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index a53aa4096..8a811fdf7 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -21,8 +21,10 @@
 namespace gpu {
 
 class CommandBufferService;
-class TransferBuffer;
+class GpuControlService;
+class GpuMemoryBufferFactory;
 class GpuScheduler;
+class TransferBuffer;
 
 namespace gles2 {
 
@@ -55,8 +57,8 @@
     bool context_lost_allowed;
     // Image manager to be used.
     gles2::ImageManager* image_manager;
-    // Image factory to be used.
-    gles2::ImageFactory* image_factory;
+    // GpuMemoryBuffer factory to be used.
+    GpuMemoryBufferFactory* gpu_memory_buffer_factory;
   };
   GLManager();
   ~GLManager();
@@ -98,6 +100,7 @@
   scoped_refptr<gles2::MailboxManager> mailbox_manager_;
   scoped_refptr<gfx::GLShareGroup> share_group_;
   scoped_ptr<CommandBufferService> command_buffer_;
+  scoped_ptr<GpuControlService> gpu_control_;
   scoped_ptr<gles2::GLES2Decoder> decoder_;
   scoped_ptr<GpuScheduler> gpu_scheduler_;
   scoped_refptr<gfx::GLSurface> surface_;
diff --git a/gpu/command_buffer_common.gypi b/gpu/command_buffer_common.gypi
index 85431e49..55e825e 100644
--- a/gpu/command_buffer_common.gypi
+++ b/gpu/command_buffer_common.gypi
@@ -21,6 +21,7 @@
     'command_buffer/common/gles2_cmd_format_autogen.h',
     'command_buffer/common/gles2_cmd_format.cc',
     'command_buffer/common/gles2_cmd_format.h',
+    'command_buffer/common/gpu_control.h',
     'command_buffer/common/id_allocator.cc',
     'command_buffer/common/id_allocator.h',
     'command_buffer/common/mailbox.cc',
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index f8e94c1..d9408b6f 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -75,13 +75,16 @@
     'command_buffer/service/gl_state_restorer_impl.cc',
     'command_buffer/service/gl_state_restorer_impl.h',
     'command_buffer/service/gl_utils.h',
-    'command_buffer/service/gpu_scheduler.h',
+    'command_buffer/service/gpu_control_service.cc',
+    'command_buffer/service/gpu_control_service.h',
+    'command_buffer/service/gpu_memory_buffer_manager.h',
     'command_buffer/service/gpu_scheduler.cc',
+    'command_buffer/service/gpu_scheduler.h',
     'command_buffer/service/gpu_scheduler_mock.h',
-    'command_buffer/service/gpu_switches.h',
     'command_buffer/service/gpu_switches.cc',
-    'command_buffer/service/gpu_tracer.h',
+    'command_buffer/service/gpu_switches.h',
     'command_buffer/service/gpu_tracer.cc',
+    'command_buffer/service/gpu_tracer.h',
     'command_buffer/service/id_manager.h',
     'command_buffer/service/id_manager.cc',
     'command_buffer/service/image_manager.cc',
diff --git a/gpu/gpu_common.gypi b/gpu/gpu_common.gypi
index da2be68..015d9c6e 100644
--- a/gpu/gpu_common.gypi
+++ b/gpu/gpu_common.gypi
@@ -39,7 +39,6 @@
       'command_buffer/client/gpu_memory_buffer_factory.h',
       'command_buffer/client/gpu_memory_buffer_tracker.cc',
       'command_buffer/client/gpu_memory_buffer_tracker.h',
-      'command_buffer/client/image_factory.h',
       'command_buffer/client/program_info_manager.cc',
       'command_buffer/client/program_info_manager.h',
       'command_buffer/client/query_tracker.cc',
diff --git a/ui/gl/gl_image.h b/ui/gl/gl_image.h
index f1d0537..8d59bc4 100644
--- a/ui/gl/gl_image.h
+++ b/ui/gl/gl_image.h
@@ -38,7 +38,9 @@
 
   // Create a GL image for a GPU Memory buffer.
   static scoped_refptr<GLImage> CreateGLImageForGpuMemoryBuffer(
-      gfx::GpuMemoryBufferHandle buffer, gfx::Size size);
+      gfx::GpuMemoryBufferHandle buffer,
+      gfx::Size size,
+      unsigned internalformat);
 
  protected:
   virtual ~GLImage();
diff --git a/ui/gl/gl_image_android.cc b/ui/gl/gl_image_android.cc
index fe871e7b..e56dc2d0 100644
--- a/ui/gl/gl_image_android.cc
+++ b/ui/gl/gl_image_android.cc
@@ -26,13 +26,16 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationEGLGLES2:
       switch (buffer.type) {
         case SHARED_MEMORY_BUFFER: {
-          scoped_refptr<GLImageShm> image(new GLImageShm(size));
+          scoped_refptr<GLImageShm> image(
+              new GLImageShm(size, internalformat));
           if (!image->Initialize(buffer))
             return NULL;
 
diff --git a/ui/gl/gl_image_mac.cc b/ui/gl/gl_image_mac.cc
index b244a22a..04dc61e 100644
--- a/ui/gl/gl_image_mac.cc
+++ b/ui/gl/gl_image_mac.cc
@@ -27,7 +27,9 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
@@ -35,7 +37,8 @@
     case kGLImplementationAppleGL:
       switch (buffer.type) {
         case SHARED_MEMORY_BUFFER: {
-          scoped_refptr<GLImageShm> image(new GLImageShm(size));
+          scoped_refptr<GLImageShm> image(
+              new GLImageShm(size, internalformat));
           if (!image->Initialize(buffer))
             return NULL;
 
diff --git a/ui/gl/gl_image_ozone.cc b/ui/gl/gl_image_ozone.cc
index c217f99..a1c13296 100644
--- a/ui/gl/gl_image_ozone.cc
+++ b/ui/gl/gl_image_ozone.cc
@@ -27,7 +27,9 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
diff --git a/ui/gl/gl_image_shm.cc b/ui/gl/gl_image_shm.cc
index 14ed836..78e81649 100644
--- a/ui/gl/gl_image_shm.cc
+++ b/ui/gl/gl_image_shm.cc
@@ -10,7 +10,11 @@
 
 namespace gfx {
 
-GLImageShm::GLImageShm(gfx::Size size) : size_(size) {
+GLImageShm::GLImageShm(gfx::Size size, unsigned internalformat)
+    : size_(size),
+      internalformat_(internalformat) {
+  // GL_RGBA8_OES is currently the only supported internalformat.
+  DCHECK_EQ(static_cast<GLenum>(GL_RGBA8_OES), internalformat);
 }
 
 GLImageShm::~GLImageShm() {
@@ -40,8 +44,23 @@
   TRACE_EVENT0("gpu", "GLImageShm::BindTexImage");
   DCHECK(shared_memory_);
 
-  const int kBytesPerPixel = 4;
-  size_t size = size_.GetArea() * kBytesPerPixel;
+  GLenum internalformat;
+  GLenum format;
+  GLenum type;
+  int bytes_per_pixel;
+  switch (internalformat_) {
+    case GL_RGBA8_OES:
+      internalformat = GL_RGBA;
+      format = GL_RGBA;
+      type = GL_UNSIGNED_BYTE;
+      bytes_per_pixel = 4;
+      break;
+    default:
+      DVLOG(0) << "Invalid format: " << internalformat_;
+      return false;
+  }
+
+  size_t size = size_.GetArea() * bytes_per_pixel;
   DCHECK(!shared_memory_->memory());
   if (!shared_memory_->Map(size)) {
     DVLOG(0) << "Failed to map shared memory.";
@@ -51,12 +70,12 @@
   DCHECK(shared_memory_->memory());
   glTexImage2D(GL_TEXTURE_2D,
                0,  // mip level
-               GL_RGBA,
+               internalformat,
                size_.width(),
                size_.height(),
                0,  // border
-               GL_RGBA,
-               GL_UNSIGNED_BYTE,
+               format,
+               type,
                shared_memory_->memory());
 
   shared_memory_->Unmap();
diff --git a/ui/gl/gl_image_shm.h b/ui/gl/gl_image_shm.h
index 70233f9a..ffdfc8b9 100644
--- a/ui/gl/gl_image_shm.h
+++ b/ui/gl/gl_image_shm.h
@@ -12,7 +12,7 @@
 
 class GL_EXPORT GLImageShm : public GLImage {
  public:
-  explicit GLImageShm(gfx::Size size);
+  GLImageShm(gfx::Size size, unsigned internalformat);
 
   bool Initialize(gfx::GpuMemoryBufferHandle buffer);
 
@@ -28,6 +28,7 @@
  private:
   scoped_ptr<base::SharedMemory> shared_memory_;
   gfx::Size size_;
+  unsigned internalformat_;
 
   DISALLOW_COPY_AND_ASSIGN(GLImageShm);
 };
diff --git a/ui/gl/gl_image_win.cc b/ui/gl/gl_image_win.cc
index 26b4a8f..1486520 100644
--- a/ui/gl/gl_image_win.cc
+++ b/ui/gl/gl_image_win.cc
@@ -27,7 +27,9 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
@@ -35,7 +37,8 @@
     case kGLImplementationEGLGLES2:
       switch (buffer.type) {
         case SHARED_MEMORY_BUFFER: {
-          scoped_refptr<GLImageShm> image(new GLImageShm(size));
+          scoped_refptr<GLImageShm> image(
+              new GLImageShm(size, internalformat));
           if (!image->Initialize(buffer))
             return NULL;
 
diff --git a/ui/gl/gl_image_x11.cc b/ui/gl/gl_image_x11.cc
index a6c09a1..6f7d8c6 100644
--- a/ui/gl/gl_image_x11.cc
+++ b/ui/gl/gl_image_x11.cc
@@ -35,7 +35,9 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
@@ -43,7 +45,8 @@
     case kGLImplementationEGLGLES2:
       switch (buffer.type) {
         case SHARED_MEMORY_BUFFER: {
-          scoped_refptr<GLImageShm> image(new GLImageShm(size));
+          scoped_refptr<GLImageShm> image(
+              new GLImageShm(size, internalformat));
           if (!image->Initialize(buffer))
             return NULL;