cc: Changes to use GL API for GpuMemoryBuffers

Corresponding gpu changes are here:
https://codereview.chromium.org/14456004/

BUG=175012

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@201718 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/cc/base/switches.cc b/cc/base/switches.cc
index e24c72a..9886ae8 100644
--- a/cc/base/switches.cc
+++ b/cc/base/switches.cc
@@ -132,6 +132,9 @@
 const char kShowNonOccludingRects[] = "show-nonoccluding-rects";
 const char kUIShowNonOccludingRects[] = "ui-show-nonoccluding-rects";
 
+// Enable the codepath that uses images within TileManager.
+const char kUseMapImage[] = "use-map-image";
+
 // Prevents the layer tree unit tests from timing out.
 const char kCCLayerTreeTestNoTimeout[] = "cc-layer-tree-test-no-timeout";
 
diff --git a/cc/base/switches.h b/cc/base/switches.h
index 7b06597..240b002 100644
--- a/cc/base/switches.h
+++ b/cc/base/switches.h
@@ -38,6 +38,7 @@
 CC_EXPORT extern const char kMaxUnusedResourceMemoryUsagePercentage[];
 CC_EXPORT extern const char kEnablePartialSwap[];
 CC_EXPORT extern const char kStrictLayerPropertyChangeChecking[];
+CC_EXPORT extern const char kUseMapImage[];
 
 // Switches for both the renderer and ui compositors.
 CC_EXPORT extern const char kUIDisablePartialSwap[];
diff --git a/cc/debug/fake_web_graphics_context_3d.cc b/cc/debug/fake_web_graphics_context_3d.cc
index d3ab18a..bbedf3d 100644
--- a/cc/debug/fake_web_graphics_context_3d.cc
+++ b/cc/debug/fake_web_graphics_context_3d.cc
@@ -340,4 +340,15 @@
                                                    WGC3Denum other) {
 }
 
+WebKit::WGC3Duint FakeWebGraphicsContext3D::createImageCHROMIUM(
+     WebKit::WGC3Dsizei width, WebKit::WGC3Dsizei height,
+     WebKit::WGC3Denum internalformat) {
+  return 0;
+}
+
+void* FakeWebGraphicsContext3D::mapImageCHROMIUM(WebKit::WGC3Duint image_id,
+                                                 WebKit::WGC3Denum access) {
+  return 0;
+}
+
 }  // namespace cc
diff --git a/cc/debug/fake_web_graphics_context_3d.h b/cc/debug/fake_web_graphics_context_3d.h
index e9d46b2..c915a9e 100644
--- a/cc/debug/fake_web_graphics_context_3d.h
+++ b/cc/debug/fake_web_graphics_context_3d.h
@@ -592,6 +592,24 @@
   virtual void drawBuffersEXT(WebKit::WGC3Dsizei m,
                               const WebKit::WGC3Denum* bufs) {}
 
+  virtual void bindTexImage2DCHROMIUM(WebKit::WGC3Denum target,
+                                      WebKit::WGC3Dint image_id) {}
+
+  // GL_CHROMIUM_gpu_memory_buffer
+  virtual WebKit::WGC3Duint createImageCHROMIUM(
+      WebKit::WGC3Dsizei width,
+      WebKit::WGC3Dsizei height,
+      WebKit::WGC3Denum internalformat);
+  virtual void destroyImageCHROMIUM(WebKit::WGC3Duint image_id) {}
+  virtual void getImageParameterivCHROMIUM(
+      WebKit::WGC3Duint image_id,
+      WebKit::WGC3Denum pname,
+      WebKit::WGC3Dint* params) {}
+  virtual void* mapImageCHROMIUM(
+      WebKit::WGC3Duint image_id,
+      WebKit::WGC3Denum access);
+  virtual void unmapImageCHROMIUM(WebKit::WGC3Duint image_id) {}
+
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeWebGraphicsContext3D);
 };
diff --git a/cc/output/delegating_renderer.cc b/cc/output/delegating_renderer.cc
index e3a784e..76093c41 100644
--- a/cc/output/delegating_renderer.cc
+++ b/cc/output/delegating_renderer.cc
@@ -80,22 +80,26 @@
 
   // TODO(danakj): We need non-GPU-specific paths for these things. This
   // renderer shouldn't need to use context3d extensions directly.
-  bool has_read_bgra = true;
-  bool has_set_visibility = true;
-  bool has_io_surface = true;
-  bool has_arb_texture_rect = true;
-  bool has_egl_image = true;
+  bool has_read_bgra = false;
+  bool has_set_visibility = false;
+  bool has_io_surface = false;
+  bool has_arb_texture_rect = false;
+  bool has_egl_image = false;
+  bool has_map_image = false;
   for (size_t i = 0; i < extensions.size(); ++i) {
-    if (extensions[i] == "GL_EXT_read_format_bgra")
+    if (extensions[i] == "GL_EXT_read_format_bgra") {
       has_read_bgra = true;
-    else if (extensions[i] == "GL_CHROMIUM_set_visibility")
+    } else if (extensions[i] == "GL_CHROMIUM_set_visibility") {
       has_set_visibility = true;
-    else if (extensions[i] == "GL_CHROMIUM_iosurface")
+    } else if (extensions[i] == "GL_CHROMIUM_iosurface") {
       has_io_surface = true;
-    else if (extensions[i] == "GL_ARB_texture_rectangle")
-      has_arb_texture_rect = true;
-    else if (extensions[i] == "GL_OES_EGL_image_external")
-      has_egl_image = true;
+    } else if (extensions[i] == "GL_ARB_texture_rectangle") {
+        has_arb_texture_rect = true;
+    } else if (extensions[i] == "GL_OES_EGL_image_external") {
+        has_egl_image = true;
+    } else if (extensions[i] == "GL_CHROMIUM_map_image") {
+      has_map_image = true;
+    }
   }
 
   if (has_io_surface)
@@ -114,6 +118,8 @@
 
   capabilities_.using_egl_image = has_egl_image;
 
+  capabilities_.using_map_image = has_map_image;
+
   return true;
 }
 
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index b151e36..15766c4 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -198,6 +198,10 @@
 
   capabilities_.using_offscreen_context3d = true;
 
+  capabilities_.using_map_image =
+      extensions.count("GL_CHROMIUM_map_image") > 0 &&
+      Settings().use_map_image;
+
   is_using_bind_uniform_ =
       extensions.count("GL_CHROMIUM_bind_uniform_location") > 0;
 
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 35457f7..7439b42 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -85,6 +85,7 @@
       size(),
       format(0),
       filter(0),
+      image_id(0),
       type(static_cast<ResourceType>(0)) {}
 
 ResourceProvider::Resource::~Resource() {}
@@ -109,6 +110,7 @@
       size(size),
       format(format),
       filter(filter),
+      image_id(0),
       type(GLTexture) {}
 
 ResourceProvider::Resource::Resource(
@@ -131,6 +133,7 @@
       size(size),
       format(format),
       filter(filter),
+      image_id(0),
       type(Bitmap) {}
 
 ResourceProvider::Child::Child() {}
@@ -308,6 +311,12 @@
   if (style == ForShutdown && resource->exported)
     lost_resource = true;
 
+  if (resource->image_id) {
+    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    DCHECK(context3d);
+    GLC(context3d, context3d->destroyImageCHROMIUM(resource->image_id));
+  }
+
   if (resource->gl_id && !resource->external) {
     WebGraphicsContext3D* context3d = output_surface_->context3d();
     DCHECK(context3d);
@@ -631,7 +640,8 @@
       use_texture_usage_hint_(false),
       use_shallow_flush_(false),
       max_texture_size_(0),
-      best_texture_format_(0) {}
+      best_texture_format_(0) {
+}
 
 bool ResourceProvider::Initialize(int highp_threshold_min) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -891,6 +901,7 @@
   Resource* resource = &it->second;
   DCHECK(!resource->external);
   DCHECK(!resource->exported);
+  DCHECK(!resource->image_id);
 
   if (resource->gl_id) {
     WebGraphicsContext3D* context3d = output_surface_->context3d();
@@ -924,6 +935,7 @@
   Resource* resource = &it->second;
   DCHECK(!resource->external);
   DCHECK(!resource->exported);
+  DCHECK(!resource->image_id);
 
   if (resource->gl_id) {
     if (!resource->gl_pixel_buffer_id)
@@ -956,6 +968,7 @@
   Resource* resource = &it->second;
   DCHECK(!resource->external);
   DCHECK(!resource->exported);
+  DCHECK(!resource->image_id);
 
   if (resource->gl_id) {
     WebGraphicsContext3D* context3d = output_surface_->context3d();
@@ -984,6 +997,7 @@
   Resource* resource = &it->second;
   DCHECK(!resource->external);
   DCHECK(!resource->exported);
+  DCHECK(!resource->image_id);
 
   if (resource->gl_id) {
     WebGraphicsContext3D* context3d = output_surface_->context3d();
@@ -992,8 +1006,7 @@
     context3d->bindBuffer(
         GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
         resource->gl_pixel_buffer_id);
-    context3d->unmapBufferCHROMIUM(
-        GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
+    context3d->unmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
     context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
   }
 }
@@ -1008,6 +1021,7 @@
   DCHECK(!resource->external);
   DCHECK(!resource->exported);
   DCHECK(ReadLockFenceHasPassed(resource));
+  DCHECK(!resource->image_id);
   LazyAllocate(resource);
 
   if (resource->gl_id) {
@@ -1073,6 +1087,7 @@
   DCHECK(!resource->pending_set_pixels);
   DCHECK(resource->gl_id || resource->allocated);
   DCHECK(ReadLockFenceHasPassed(resource));
+  DCHECK(!resource->image_id);
 
   bool allocate = !resource->allocated;
   resource->allocated = true;
@@ -1242,4 +1257,118 @@
   resource->enable_read_lock_fences = enable;
 }
 
+void ResourceProvider::AcquireImage(ResourceId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ResourceMap::iterator it = resources_.find(id);
+  CHECK(it != resources_.end());
+  Resource* resource = &it->second;
+
+  DCHECK(resource->gl_id);
+  DCHECK(!resource->pixels);
+  DCHECK(!resource->external);
+  DCHECK(!resource->exported);
+
+  if (resource->image_id != 0) {
+    // If we had previously allocated an image for this resource,
+    // release it before allocating a new one to prevent leaks.
+    ReleaseImage(id);
+  }
+
+  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  DCHECK(context3d);
+  resource->image_id = context3d->createImageCHROMIUM(
+      resource->size.width(), resource->size.height(), GL_RGBA8_OES);
+}
+
+void ResourceProvider::ReleaseImage(ResourceId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ResourceMap::iterator it = resources_.find(id);
+  CHECK(it != resources_.end());
+  Resource* resource = &it->second;
+
+  DCHECK(!resource->external);
+  DCHECK(!resource->exported);
+  DCHECK(!resource->pixels);
+
+  if (resource->image_id == 0)
+    return;
+
+  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  DCHECK(context3d);
+  context3d->destroyImageCHROMIUM(resource->image_id);
+  resource->image_id = 0;
+}
+
+uint8_t* ResourceProvider::MapImage(ResourceId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ResourceMap::iterator it = resources_.find(id);
+  CHECK(it != resources_.end());
+  Resource* resource = &it->second;
+
+  DCHECK(ReadLockFenceHasPassed(resource));
+  DCHECK(!resource->external);
+  DCHECK(!resource->exported);
+  DCHECK(!resource->pixels);
+  DCHECK(resource->image_id);
+
+  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  DCHECK(context3d);
+  return static_cast<uint8_t*>(
+      context3d->mapImageCHROMIUM(resource->image_id, GL_READ_WRITE));
+}
+
+void ResourceProvider::UnmapImage(ResourceId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ResourceMap::iterator it = resources_.find(id);
+  CHECK(it != resources_.end());
+  Resource* resource = &it->second;
+
+  DCHECK(!resource->external);
+  DCHECK(!resource->exported);
+  DCHECK(!resource->pixels);
+  DCHECK(resource->image_id);
+
+  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  DCHECK(context3d);
+  context3d->unmapImageCHROMIUM(resource->image_id);
+}
+
+void ResourceProvider::BindImage(ResourceId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ResourceMap::iterator it = resources_.find(id);
+  CHECK(it != resources_.end());
+  Resource* resource = &it->second;
+
+  DCHECK(!resource->external);
+  DCHECK(!resource->exported);
+  DCHECK(!resource->pixels);
+  DCHECK(resource->image_id);
+  DCHECK(resource->gl_id);
+
+  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  DCHECK(context3d);
+  context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id);
+  context3d->bindTexImage2DCHROMIUM(GL_TEXTURE_2D, resource->image_id);
+}
+
+int ResourceProvider::GetImageStride(ResourceId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ResourceMap::iterator it = resources_.find(id);
+  CHECK(it != resources_.end());
+  Resource* resource = &it->second;
+
+  DCHECK(!resource->external);
+  DCHECK(!resource->exported);
+  DCHECK(!resource->pixels);
+  DCHECK(resource->image_id);
+
+  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  DCHECK(context3d);
+  int stride = 0;
+  context3d->getImageParameterivCHROMIUM(
+      resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, &stride);
+  return stride;
+}
+
+
 }  // namespace cc
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 6f146d9..b4c8c92 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -292,6 +292,22 @@
   bool DidSetPixelsComplete(ResourceId id);
   void AbortSetPixels(ResourceId id);
 
+  // Acquire and release an image. The image allows direct
+  // manipulation of texture memory.
+  void AcquireImage(ResourceId id);
+  void ReleaseImage(ResourceId id);
+
+  // Maps the acquired image so that its pixels could be modified.
+  // Unmap is called when all pixels are set.
+  uint8_t* MapImage(ResourceId id);
+  void UnmapImage(ResourceId id);
+
+  // Binds the image to a texture.
+  void BindImage(ResourceId id);
+
+  // Returns the stride for the image.
+  int GetImageStride(ResourceId id);
+
   // For tests only! This prevents detecting uninitialized reads.
   // Use SetPixels or LockForWrite to allocate implicitly.
   void AllocateForTesting(ResourceId id);
@@ -347,6 +363,7 @@
     GLenum format;
     // TODO(skyostil): Use a separate sampler object for filter state.
     GLenum filter;
+    unsigned image_id;
     ResourceType type;
   };
   typedef base::hash_map<ResourceId, Resource> ResourceMap;
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index c3ac798..91e8d00 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -24,6 +24,7 @@
 using testing::Mock;
 using testing::NiceMock;
 using testing::Return;
+using testing::SetArgPointee;
 using testing::StrictMock;
 using testing::_;
 using WebKit::WGC3Dbyte;
@@ -1235,7 +1236,15 @@
                     WGC3Denum format,
                     WGC3Denum type,
                     const void* pixels));
-  MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(WGC3Denum target));
+  MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(WGC3Denum));
+  MOCK_METHOD3(createImageCHROMIUM, WGC3Duint(WGC3Dsizei, WGC3Dsizei,
+                                              WGC3Denum));
+  MOCK_METHOD1(destroyImageCHROMIUM, void(WGC3Duint));
+  MOCK_METHOD2(mapImageCHROMIUM, void*(WGC3Duint, WGC3Denum));
+  MOCK_METHOD3(getImageParameterivCHROMIUM, void(WGC3Duint, WGC3Denum,
+                                                 GLint*));
+  MOCK_METHOD1(unmapImageCHROMIUM, void(WGC3Duint));
+  MOCK_METHOD2(bindTexImage2DCHROMIUM, void(WGC3Denum, WGC3Dint));
 };
 
 TEST_P(ResourceProviderTest, TextureAllocation) {
@@ -1417,6 +1426,82 @@
   Mock::VerifyAndClearExpectations(context);
 }
 
+TEST_P(ResourceProviderTest, GpuMemoryBuffers) {
+  // Only for GL textures.
+  if (GetParam() != ResourceProvider::GLTexture)
+    return;
+  scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
+      static_cast<WebKit::WebGraphicsContext3D*>(
+          new StrictMock<AllocationTrackingContext3D>));
+  scoped_ptr<OutputSurface> output_surface(
+      FakeOutputSurface::Create3d(mock_context.Pass()));
+
+  const int kWidth = 2;
+  const int kHeight = 2;
+  gfx::Size size(kWidth, kHeight);
+  WGC3Denum format = GL_RGBA;
+  ResourceProvider::ResourceId id = 0;
+  const unsigned kTextureId = 123u;
+  const unsigned kImageId = 234u;
+
+  AllocationTrackingContext3D* context =
+      static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
+  scoped_ptr<ResourceProvider> resource_provider(
+      ResourceProvider::Create(output_surface.get(), 0));
+
+  EXPECT_CALL(*context, createTexture())
+      .WillOnce(Return(kTextureId))
+      .RetiresOnSaturation();
+
+  EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId))
+      .Times(1)
+      .RetiresOnSaturation();
+  id = resource_provider->CreateResource(
+      size, format, ResourceProvider::TextureUsageAny);
+  EXPECT_CALL(*context, createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES))
+      .WillOnce(Return(kImageId))
+      .RetiresOnSaturation();
+  resource_provider->AcquireImage(id);
+
+  EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
+      .Times(1)
+      .RetiresOnSaturation();
+  resource_provider->BindImage(id);
+
+  void* dummy_mapped_buffer_address = NULL;
+  EXPECT_CALL(*context, mapImageCHROMIUM(kImageId, GL_READ_WRITE))
+      .WillOnce(Return(dummy_mapped_buffer_address))
+      .RetiresOnSaturation();
+  resource_provider->MapImage(id);
+
+  const int kStride = 4;
+  EXPECT_CALL(*context, getImageParameterivCHROMIUM(kImageId,
+                                                    GL_IMAGE_ROWBYTES_CHROMIUM,
+                                                    _))
+      .WillOnce(SetArgPointee<2>(kStride))
+      .RetiresOnSaturation();
+  int stride = resource_provider->GetImageStride(id);
+  EXPECT_EQ(kStride, stride);
+
+  EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId))
+      .Times(1)
+      .RetiresOnSaturation();
+  resource_provider->UnmapImage(id);
+
+  EXPECT_CALL(*context, destroyImageCHROMIUM(kImageId))
+      .Times(1)
+      .RetiresOnSaturation();
+  resource_provider->ReleaseImage(id);
+
+  // Texture will be deleted when ResourceProvider destructor is
+  // called when it goes out of scope when this method returns.
+  EXPECT_CALL(*context, deleteTexture(kTextureId))
+      .Times(1)
+      .RetiresOnSaturation();
+}
+
 INSTANTIATE_TEST_CASE_P(
     ResourceProviderTests,
     ResourceProviderTest,
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 5af8d7a..a318c3c 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -110,7 +110,8 @@
     ResourceProvider* resource_provider,
     size_t num_raster_threads,
     bool use_color_estimator,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation) {
+    RenderingStatsInstrumentation* rendering_stats_instrumentation,
+    bool use_map_image) {
   scoped_ptr<RasterWorkerPool> raster_worker_pool =
       RasterWorkerPool::Create(num_raster_threads);
   return make_scoped_ptr(new TileManager(client,
@@ -118,7 +119,8 @@
                                          raster_worker_pool.Pass(),
                                          num_raster_threads,
                                          use_color_estimator,
-                                         rendering_stats_instrumentation));
+                                         rendering_stats_instrumentation,
+                                         use_map_image));
 }
 
 TileManager::TileManager(
@@ -127,7 +129,8 @@
     scoped_ptr<RasterWorkerPool> raster_worker_pool,
     size_t num_raster_threads,
     bool use_color_estimator,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation)
+    RenderingStatsInstrumentation* rendering_stats_instrumentation,
+    bool use_map_image)
     : client_(client),
       resource_pool_(ResourcePool::Create(resource_provider)),
       raster_worker_pool_(raster_worker_pool.Pass()),
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index 7aa07c9..543539d 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -67,8 +67,8 @@
       ResourceProvider* resource_provider,
       size_t num_raster_threads,
       bool use_color_estimator,
-      RenderingStatsInstrumentation* rendering_stats_instrumentation);
-
+      RenderingStatsInstrumentation* rendering_stats_instrumentation,
+      bool use_map_image);
   virtual ~TileManager();
 
   const GlobalStateThatImpactsTilePriority& GlobalState() const {
@@ -107,7 +107,8 @@
               scoped_ptr<RasterWorkerPool> raster_worker_pool,
               size_t num_raster_threads,
               bool use_color_estimator,
-              RenderingStatsInstrumentation* rendering_stats_instrumentation);
+              RenderingStatsInstrumentation* rendering_stats_instrumentation,
+              bool use_map_image);
 
   // Methods called by Tile
   friend class Tile;
diff --git a/cc/test/fake_picture_layer_tiling_client.cc b/cc/test/fake_picture_layer_tiling_client.cc
index 3a838dd..ebd530a7 100644
--- a/cc/test/fake_picture_layer_tiling_client.cc
+++ b/cc/test/fake_picture_layer_tiling_client.cc
@@ -27,7 +27,8 @@
                                         NULL,
                                         1,
                                         false,
-                                        &stats_instrumentation_)),
+                                        &stats_instrumentation_,
+                                        false)),
       pile_(new FakeInfinitePicturePileImpl()),
       twin_tiling_(NULL),
       allow_create_tile_(true) {}
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index c3d1349..f40dbaa 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -14,5 +14,6 @@
                   RasterWorkerPool::Create(1),
                   1,
                   false,
-                  NULL) {}
+                  NULL,
+                  false) {}
 }
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 97a2760..de019b0 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -54,7 +54,8 @@
       allow_partial_texture_updates(false),
       using_offscreen_context3d(false),
       max_texture_size(0),
-      avoid_pow2_textures(false) {}
+      avoid_pow2_textures(false),
+      using_map_image(false) {}
 
 RendererCapabilities::~RendererCapabilities() {}
 
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index e134cb0..ea2997a 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -82,6 +82,7 @@
   bool using_offscreen_context3d;
   int max_texture_size;
   bool avoid_pow2_textures;
+  bool using_map_image;
 };
 
 class CC_EXPORT LayerTreeHost : NON_EXPORTED_BASE(public RateLimiterClient) {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 9ee229b..f68965c 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1433,15 +1433,6 @@
     if (!resource_provider)
       return false;
 
-    if (settings_.impl_side_painting) {
-      tile_manager_ = TileManager::Create(this,
-                                          resource_provider.get(),
-                                          settings_.num_raster_threads,
-                                          settings_.use_color_estimator,
-                                          rendering_stats_instrumentation_);
-      UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
-    }
-
     if (output_surface->capabilities().has_parent_compositor) {
       renderer_ = DelegatingRenderer::Create(this, output_surface.get(),
                                              resource_provider.get());
@@ -1459,6 +1450,17 @@
     if (!renderer_)
       return false;
 
+    if (settings_.impl_side_painting) {
+      bool using_map_image = GetRendererCapabilities().using_map_image;
+      tile_manager_ = TileManager::Create(this,
+                                          resource_provider.get(),
+                                          settings_.num_raster_threads,
+                                          settings_.use_color_estimator,
+                                          rendering_stats_instrumentation_,
+                                          using_map_image);
+      UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
+    }
+
     resource_provider_ = resource_provider.Pass();
   }
 
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 74b03d2..5d03f8e 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -55,7 +55,8 @@
       max_unused_resource_memory_percentage(100),
       highp_threshold_min(0),
       force_direct_layer_drawing(false),
-      strict_layer_property_change_checking(false) {
+      strict_layer_property_change_checking(false),
+      use_map_image(false) {
   // TODO(danakj): Renable surface caching when we can do it more realiably.
   // crbug.com/170713
   cache_render_pass_contents = false;
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 5295e3f..179b395 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -60,6 +60,7 @@
   int highp_threshold_min;
   bool force_direct_layer_drawing;  // With Skia GPU backend.
   bool strict_layer_property_change_checking;
+  bool use_map_image;
 
   LayerTreeDebugState initial_debug_state;
 };
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 5508a5d..ec64a5d 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -160,6 +160,7 @@
       cc::switches::kTraceOverdraw,
       cc::switches::kUIDisablePartialSwap,
       cc::switches::kUIEnablePerTilePainting,
+      cc::switches::kUseMapImage,
       chromeos::switches::kDbusStub,
       chromeos::switches::kDisableLoginAnimations,
       chromeos::switches::kDisableOobeAnimation,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 57c2191..269900c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -978,6 +978,7 @@
     cc::switches::kTopControlsHideThreshold,
     cc::switches::kTopControlsShowThreshold,
     cc::switches::kTraceOverdraw,
+    cc::switches::kUseMapImage,
   };
   renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
                                  arraysize(kSwitchNames));
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 55a7b49..ada1e77 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -268,6 +268,8 @@
   settings.strict_layer_property_change_checking =
       cmd->HasSwitch(cc::switches::kStrictLayerPropertyChangeChecking);
 
+  settings.use_map_image = cmd->HasSwitch(cc::switches::kUseMapImage);
+
 #if defined(OS_ANDROID)
   // TODO(danakj): Move these to the android code.
   settings.can_use_lcd_text = false;