Revved to chromium 4dfb55c9cf0950b8bac8b10070c9b8f3e7de66c2 refs/remotes/origin/HEAD
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index b77dfca..8239940 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -43,6 +43,7 @@
     "//gpu/command_buffer/common",
     "//gpu/command_buffer/service",
     "//gpu/config",
+    "//gpu/ipc",
   ]
 }
 
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt
index 154f91e..2974e43 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt
@@ -8,7 +8,7 @@
 
 Version
 
-    Last Modifed Date: Apr 30, 2014
+    Last Modifed Date: Oct 7, 2014
 
 Dependencies
 
@@ -16,19 +16,8 @@
 
 Overview
 
-    This extension allows for more efficient uploading of texture data through
-    Chromium's OpenGL ES 2.0 implementation as well as enable hardware overlay
-    support by providing ability to create buffers capable of being scanned out
-    directly by the display controller.
-
-    For security reasons Chromium accesses the GPU from a separate process. User
-    processes are not allowed to access the GPU directly. This multi-process
-    architechure has the advantage that GPU operations can be secured and
-    pipelined but it has the disadvantage that all data that is going to be
-    passed to GPU must first be made available to the separate GPU process.
-
-    This extension helps the application directly allocate and access texture
-    memory.
+    This extension defines a new resource type that is suitable for
+    sharing 2D arrays of image data between client APIs.
 
 Issues
 
@@ -36,73 +25,32 @@
 
 New Tokens
 
-    Accepted by the <pname> parameter of GetImageParameterivCHROMIUM:
-
-        IMAGE_ROWBYTES_CHROMIUM 0x78F0
-
-    Accepted by the <usage> parameter of CreateImageCHROMIUM:
-
-        IMAGE_MAP_CHROMIUM 0x78F1
-        IMAGE_SCANOUT_CHROMIUM 0x78F2
+    None
 
 New Procedures and Functions
 
-    GLuint CreateImageCHROMIUM(GLsizei width, GLsizei height,
-                               GLenum internalformat, GLenum usage)
+    GLuint CreateImageCHROMIUM(ClientBuffer buffer,
+                               GLsizei width,
+                               GLsizei height,
+                               GLenum internalformat)
 
-    Allocate an image with width equal to <width> and height equal
-    to <height> stored in format <internalformat>.
+    Create an image from <buffer> with width equal to <width> and
+    height equal to <height> and format equal to <internalformat>.
 
-    Returns a unique identifier for the allocated image that could be used
-    in subsequent operations.
+    Returns a unique identifier for the image that could be used in
+    subsequent operations.
 
     INVALID_VALUE is generated if <width> or <height> is nonpositive.
 
-    INVALID_ENUM is generated if <usage> is not one of
-    IMAGE_MAP_CHROMIUM and IMAGE_SCANOUT_CHROMIUM.
+    INVALID_ENUM is generated if <internalformat> is not one of
+    RGB or RGBA.
 
     void DestroyImageCHROMIUM(GLuint image_id)
 
-    Frees the image previously allocated by a call to CreateImageCHROMIUM.
+    Frees the image previously created by a call to CreateImageCHROMIUM.
 
     INVALID_OPERATION is generated if <image_id> is not a valid image id.
 
-    void* MapImageCHROMIUM(GLuint image_id)
-
-    Returns a pointer to in the user memory for the application to modify
-    the image. It is illegal to call this function on an image not created
-    with IMAGE_MAP_CHROMIUM usage.
-
-    INVALID_OPERATION is generated if <image_id> is not a valid image id.
-
-    INVALID_OPERATION is generated if the image was already mapped by a previous
-    call to this method.
-
-    void UnmapImageCHROMIUM(GLuint image_id)
-
-    Removes the mapping created by a call to MapImageCHROMIUM.
-
-    Note that after calling UnmapImageCHROMIUM the application should assume
-    that the memory returned by MapImageCHROMIUM is off limits and is no longer
-    accessible by the application. Accessing it after calling
-    UnmapImageCHROMIUM will produce undefined results.
-
-    INVALID_OPERATION is generated if <image_id> is not a valid image id.
-
-    INVALID_OPERATION is generated if the image was not already mapped by a
-    previous call to MapImageCHROMIUM.
-
-    void GetImageParameterivCHROMIUM(GLuint image_id, GLenum pname,
-                                     GLint* params)
-
-    Sets <params> to the integer value of the parameter specified by <pname>
-    for the image specified by <image_id>. <params> is expected to be
-    properly allocated before calling this method.
-
-    INVALID_OPERATION is generated if <image_id> is not a valid image id.
-
-    INVALID_ENUM is generated if <pname> is not IMAGE_ROWBYTES_CHROMIUM.
-
 Errors
 
     None.
@@ -115,3 +63,4 @@
 
     5/9/2013    Documented the extension
     4/30/2014   Moved usage flag to creation function.
+    10/7/2014   Remove map/unmap API.
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index ddc5730..843cb31 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -185,8 +185,6 @@
 #define glEnableFeatureCHROMIUM GLES2_GET_FUN(EnableFeatureCHROMIUM)
 #define glMapBufferCHROMIUM GLES2_GET_FUN(MapBufferCHROMIUM)
 #define glUnmapBufferCHROMIUM GLES2_GET_FUN(UnmapBufferCHROMIUM)
-#define glMapImageCHROMIUM GLES2_GET_FUN(MapImageCHROMIUM)
-#define glUnmapImageCHROMIUM GLES2_GET_FUN(UnmapImageCHROMIUM)
 #define glMapBufferSubDataCHROMIUM GLES2_GET_FUN(MapBufferSubDataCHROMIUM)
 #define glUnmapBufferSubDataCHROMIUM GLES2_GET_FUN(UnmapBufferSubDataCHROMIUM)
 #define glMapTexSubImage2DCHROMIUM GLES2_GET_FUN(MapTexSubImage2DCHROMIUM)
@@ -202,7 +200,6 @@
 #define glCreateStreamTextureCHROMIUM GLES2_GET_FUN(CreateStreamTextureCHROMIUM)
 #define glCreateImageCHROMIUM GLES2_GET_FUN(CreateImageCHROMIUM)
 #define glDestroyImageCHROMIUM GLES2_GET_FUN(DestroyImageCHROMIUM)
-#define glGetImageParameterivCHROMIUM GLES2_GET_FUN(GetImageParameterivCHROMIUM)
 #define glCreateGpuMemoryBufferImageCHROMIUM \
   GLES2_GET_FUN(CreateGpuMemoryBufferImageCHROMIUM)
 #define glGetTranslatedShaderSourceANGLE \
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h
index 5199864..b524112 100644
--- a/gpu/GLES2/gl2extchromium.h
+++ b/gpu/GLES2/gl2extchromium.h
@@ -106,38 +106,22 @@
 #ifndef GL_CHROMIUM_image
 #define GL_CHROMIUM_image 1
 
-#ifndef GL_IMAGE_ROWBYTES_CHROMIUM
-#define GL_IMAGE_ROWBYTES_CHROMIUM 0x78F0
-#endif
-
-#ifndef GL_IMAGE_MAP_CHROMIUM
-#define GL_IMAGE_MAP_CHROMIUM 0x78F1
-#endif
-
-#ifndef GL_IMAGE_SCANOUT_CHROMIUM
-#define GL_IMAGE_SCANOUT_CHROMIUM 0x78F2
-#endif
+typedef struct _ClientBuffer* ClientBuffer;
 
 #ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL GLuint GL_APIENTRY glCreateImageCHROMIUM(GLsizei width,
+GL_APICALL GLuint GL_APIENTRY glCreateImageCHROMIUM(ClientBuffer buffer,
+                                                    GLsizei width,
                                                     GLsizei height,
-                                                    GLenum internalformat,
-                                                    GLenum usage);
+                                                    GLenum internalformat);
 GL_APICALL void GL_APIENTRY glDestroyImageCHROMIUM(GLuint image_id);
-GL_APICALL void GL_APIENTRY glGetImageParameterivCHROMIUM(
-    GLuint image_id, GLenum pname, GLint* params);
-GL_APICALL void* GL_APIENTRY glMapImageCHROMIUM(GLuint image_id);
-GL_APICALL void GL_APIENTRY glUnmapImageCHROMIUM(GLuint image_id);
 #endif
 typedef GLuint(GL_APIENTRYP PFNGLCREATEIMAGECHROMIUMPROC)(
+    ClientBuffer buffer,
     GLsizei width,
     GLsizei height,
-    GLenum internalformat,
-    GLenum usage);
+    GLenum internalformat);
 typedef void (
     GL_APIENTRYP PFNGLDESTROYIMAGECHROMIUMPROC)(GLuint image_id);
-typedef void* (GL_APIENTRYP PFNGLMAPIMAGECHROMIUMPROC)(GLuint image_id);
-typedef void (GL_APIENTRYP PFNGLUNMAPIMAGECHROMIUMPROC)(GLuint image_id);
 #endif  /* GL_CHROMIUM_image */
 
   /* GL_CHROMIUM_gpu_memory_buffer_image */
@@ -159,7 +143,7 @@
     GLenum internalformat,
     GLenum usage);
 #endif
-typedef GLuint(GL_APIENTRYP PFNGLCREATEGPUMEMORYBUFFERIMAGECHROMIUMPROC) (
+typedef GLuint(GL_APIENTRYP PFNGLCREATEGPUMEMORYBUFFERIMAGECHROMIUMPROC)(
     GLsizei width,
     GLsizei height,
     GLenum internalformat,
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index a6a6323..14191f2 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1485,7 +1485,8 @@
   'CreateImageCHROMIUM': {
     'type': 'Manual',
     'cmd_args':
-        'GLsizei width, GLsizei height, GLenum internalformat, GLenum usage',
+        'ClientBuffer buffer, GLsizei width, GLsizei height, '
+        'GLenum internalformat',
     'result': ['GLuint'],
     'client_test': False,
     'gen_cmd': False,
@@ -1500,14 +1501,6 @@
     'extension': True,
     'chromium': True,
   },
-  'GetImageParameterivCHROMIUM': {
-    'type': 'Manual',
-    'client_test': False,
-    'gen_cmd': False,
-    'expectation': False,
-    'extension': True,
-    'chromium': True,
-  },
   'CreateGpuMemoryBufferImageCHROMIUM': {
     'type': 'Manual',
     'cmd_args':
@@ -1992,12 +1985,6 @@
     'client_test': False,
     'pepper_interface': 'ChromiumMapSub',
   },
-  'MapImageCHROMIUM': {
-    'gen_cmd': False,
-    'extension': True,
-    'chromium': True,
-    'client_test': False,
-  },
   'MapTexSubImage2DCHROMIUM': {
     'gen_cmd': False,
     'extension': True,
@@ -2237,12 +2224,6 @@
     'client_test': False,
     'pepper_interface': 'ChromiumMapSub',
   },
-  'UnmapImageCHROMIUM': {
-    'gen_cmd': False,
-    'extension': True,
-    'chromium': True,
-    'client_test': False,
-  },
   'UnmapTexSubImage2DCHROMIUM': {
     'gen_cmd': False,
     'extension': True,
@@ -5867,8 +5848,10 @@
           "  helper_->%s(%s%sGetResultShmId(), GetResultShmOffset());\n" %
                  (func.name, arg_string, comma))
       file.Write("  WaitForCmd();\n")
-      file.Write("  %s result_value = *result;\n" % func.return_type)
-      file.Write('  GPU_CLIENT_LOG("returned " << result_value);\n')
+      file.Write("  %s result_value = *result" % func.return_type)
+      if func.return_type == "GLboolean":
+        file.Write(" != 0")
+      file.Write(';\n  GPU_CLIENT_LOG("returned " << result_value);\n')
       file.Write("  CheckGLError();\n")
       file.Write("  return result_value;\n")
       file.Write("}\n")
diff --git a/gpu/command_buffer/client/BUILD.gn b/gpu/command_buffer/client/BUILD.gn
index afd03a4..9b4749f 100644
--- a/gpu/command_buffer/client/BUILD.gn
+++ b/gpu/command_buffer/client/BUILD.gn
@@ -81,9 +81,6 @@
   "gles2_trace_implementation.cc",
   "gles2_trace_implementation.h",
   "gles2_trace_implementation_impl_autogen.h",
-  "gpu_memory_buffer_factory.h",
-  "gpu_memory_buffer_tracker.cc",
-  "gpu_memory_buffer_tracker.h",
   "gpu_switches.cc",
   "gpu_switches.h",
   "program_info_manager.cc",
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h
index d545045..51c6b6d 100644
--- a/gpu/command_buffer/client/client_test_helper.h
+++ b/gpu/command_buffer/client/client_test_helper.h
@@ -88,13 +88,17 @@
   virtual ~MockClientGpuControl();
 
   MOCK_METHOD0(GetCapabilities, Capabilities());
-  MOCK_METHOD5(CreateGpuMemoryBuffer,
-               gfx::GpuMemoryBuffer*(size_t width,
-                                     size_t height,
-                                     unsigned internalformat,
-                                     unsigned usage,
-                                     int32* id));
-  MOCK_METHOD1(DestroyGpuMemoryBuffer, void(int32 id));
+  MOCK_METHOD4(CreateImage,
+               int32(ClientBuffer buffer,
+                     size_t width,
+                     size_t height,
+                     unsigned internalformat));
+  MOCK_METHOD1(DestroyImage, void(int32 id));
+  MOCK_METHOD4(CreateGpuMemoryBufferImage,
+               int32(size_t width,
+                     size_t height,
+                     unsigned internalformat,
+                     unsigned usage));
   MOCK_METHOD0(InsertSyncPoint, uint32());
   MOCK_METHOD0(InsertFutureSyncPoint, uint32());
   MOCK_METHOD1(RetireSyncPoint, void(uint32 id));
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index e11cf63..71e3c82 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -721,12 +721,6 @@
 GLboolean GLES2UnmapBufferCHROMIUM(GLuint target) {
   return gles2::GetGLContext()->UnmapBufferCHROMIUM(target);
 }
-void* GLES2MapImageCHROMIUM(GLuint image_id) {
-  return gles2::GetGLContext()->MapImageCHROMIUM(image_id);
-}
-void GLES2UnmapImageCHROMIUM(GLuint image_id) {
-  gles2::GetGLContext()->UnmapImageCHROMIUM(image_id);
-}
 void* GLES2MapBufferSubDataCHROMIUM(GLuint target,
                                     GLintptr offset,
                                     GLsizeiptr size,
@@ -780,21 +774,16 @@
 GLuint GLES2CreateStreamTextureCHROMIUM(GLuint texture) {
   return gles2::GetGLContext()->CreateStreamTextureCHROMIUM(texture);
 }
-GLuint GLES2CreateImageCHROMIUM(GLsizei width,
+GLuint GLES2CreateImageCHROMIUM(ClientBuffer buffer,
+                                GLsizei width,
                                 GLsizei height,
-                                GLenum internalformat,
-                                GLenum usage) {
+                                GLenum internalformat) {
   return gles2::GetGLContext()->CreateImageCHROMIUM(
-      width, height, internalformat, usage);
+      buffer, width, height, internalformat);
 }
 void GLES2DestroyImageCHROMIUM(GLuint image_id) {
   gles2::GetGLContext()->DestroyImageCHROMIUM(image_id);
 }
-void GLES2GetImageParameterivCHROMIUM(GLuint image_id,
-                                      GLenum pname,
-                                      GLint* params) {
-  gles2::GetGLContext()->GetImageParameterivCHROMIUM(image_id, pname, params);
-}
 GLuint GLES2CreateGpuMemoryBufferImageCHROMIUM(GLsizei width,
                                                GLsizei height,
                                                GLenum internalformat,
@@ -1650,14 +1639,6 @@
      reinterpret_cast<GLES2FunctionPointer>(glUnmapBufferCHROMIUM),
     },
     {
-     "glMapImageCHROMIUM",
-     reinterpret_cast<GLES2FunctionPointer>(glMapImageCHROMIUM),
-    },
-    {
-     "glUnmapImageCHROMIUM",
-     reinterpret_cast<GLES2FunctionPointer>(glUnmapImageCHROMIUM),
-    },
-    {
      "glMapBufferSubDataCHROMIUM",
      reinterpret_cast<GLES2FunctionPointer>(glMapBufferSubDataCHROMIUM),
     },
@@ -1711,10 +1692,6 @@
      reinterpret_cast<GLES2FunctionPointer>(glDestroyImageCHROMIUM),
     },
     {
-     "glGetImageParameterivCHROMIUM",
-     reinterpret_cast<GLES2FunctionPointer>(glGetImageParameterivCHROMIUM),
-    },
-    {
      "glCreateGpuMemoryBufferImageCHROMIUM",
      reinterpret_cast<GLES2FunctionPointer>(
          glCreateGpuMemoryBufferImageCHROMIUM),
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index aabfa45..96a71fc 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -18,14 +18,12 @@
 #include "base/bind.h"
 #include "gpu/command_buffer/client/buffer_tracker.h"
 #include "gpu/command_buffer/client/gpu_control.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
 #include "gpu/command_buffer/client/program_info_manager.h"
 #include "gpu/command_buffer/client/query_tracker.h"
 #include "gpu/command_buffer/client/transfer_buffer.h"
 #include "gpu/command_buffer/client/vertex_array_object_manager.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/common/trace_event.h"
-#include "ui/gfx/gpu_memory_buffer.h"
 
 #if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
 #define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
@@ -191,7 +189,6 @@
 
   query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
   buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
-  gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
 
   query_id_allocator_.reset(new IdAllocator());
 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
@@ -2831,7 +2828,7 @@
   WaitForCmd();
   helper_->SetBucketSize(kResultBucketId, 0);
   GPU_CLIENT_LOG("   returned " << GLES2Util::GetStringBool(*result));
-  return *result;
+  return *result != 0;
 }
 
 void* GLES2Implementation::MapBufferSubDataCHROMIUM(
@@ -3937,10 +3934,10 @@
 
 }  // namespace
 
-GLuint GLES2Implementation::CreateImageCHROMIUMHelper(GLsizei width,
+GLuint GLES2Implementation::CreateImageCHROMIUMHelper(ClientBuffer buffer,
+                                                      GLsizei width,
                                                       GLsizei height,
-                                                      GLenum internalformat,
-                                                      GLenum usage) {
+                                                      GLenum internalformat) {
   if (width <= 0) {
     SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
     return 0;
@@ -3950,48 +3947,44 @@
     SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
     return 0;
   }
+
+  if (!ValidImageFormat(internalformat)) {
+    SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "invalid format");
+    return 0;
+  }
+
   // Flush the command stream to ensure ordering in case the newly
   // returned image_id has recently been in use with a different buffer.
   helper_->CommandBufferHelper::Flush();
-
-  // Create new buffer.
-  GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
-      width, height, internalformat, usage);
-  if (buffer_id == 0) {
-    SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
+  int32_t image_id =
+      gpu_control_->CreateImage(buffer, width, height, internalformat);
+  if (image_id < 0) {
+    SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "image_id < 0");
     return 0;
   }
-  return buffer_id;
+  return image_id;
 }
 
-GLuint GLES2Implementation::CreateImageCHROMIUM(GLsizei width,
+GLuint GLES2Implementation::CreateImageCHROMIUM(ClientBuffer buffer,
+                                                GLsizei width,
                                                 GLsizei height,
-                                                GLenum internalformat,
-                                                GLenum usage) {
+                                                GLenum internalformat) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_LOG(
-      "[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width << ", "
-          << height << ", "
-          << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
-          << GLES2Util::GetStringTextureInternalFormat(usage) << ")");
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM(" << width
+                     << ", " << height << ", "
+                     << GLES2Util::GetStringImageInternalFormat(internalformat)
+                     << ")");
   GLuint image_id =
-      CreateImageCHROMIUMHelper(width, height, internalformat, usage);
+      CreateImageCHROMIUMHelper(buffer, width, height, internalformat);
   CheckGLError();
   return image_id;
 }
 
 void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
-  gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
-      image_id);
-  if (!gpu_buffer) {
-    SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
-    return;
-  }
-
   // Flush the command stream to make sure all pending commands
   // that may refer to the image_id are executed on the service side.
   helper_->CommandBufferHelper::Flush();
-  gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
+  gpu_control_->DestroyImage(image_id);
 }
 
 void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
@@ -4002,93 +3995,6 @@
   CheckGLError();
 }
 
-void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
-  gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
-      image_id);
-  if (!gpu_buffer) {
-    SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
-    return;
-  }
-
-  if (!gpu_buffer->IsMapped()) {
-    SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
-    return;
-  }
-  gpu_buffer->Unmap();
-}
-
-void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
-  GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
-       << image_id << ")");
-
-  UnmapImageCHROMIUMHelper(image_id);
-  CheckGLError();
-}
-
-void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id) {
-  gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
-      image_id);
-  if (!gpu_buffer) {
-    SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
-    return NULL;
-  }
-
-  if (gpu_buffer->IsMapped()) {
-    SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
-    return NULL;
-  }
-
-  return gpu_buffer->Map();
-}
-
-void* GLES2Implementation::MapImageCHROMIUM(GLuint image_id) {
-  GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM(" << image_id
-                     << ")");
-
-  void* mapped = MapImageCHROMIUMHelper(image_id);
-  CheckGLError();
-  return mapped;
-}
-
-void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
-    GLuint image_id, GLenum pname, GLint* params) {
-  if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
-    SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
-               "invalid parameter");
-    return;
-  }
-
-  gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
-      image_id);
-  if (!gpu_buffer) {
-    SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
-               "invalid image");
-    return;
-  }
-
-  if (!gpu_buffer->IsMapped()) {
-    SetGLError(
-        GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM", "not mapped");
-    return;
-  }
-
-  *params = gpu_buffer->GetStride();
-}
-
-void GLES2Implementation::GetImageParameterivCHROMIUM(
-    GLuint image_id, GLenum pname, GLint* params) {
-  GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
-  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
-      << image_id << ", "
-      << GLES2Util::GetStringBufferParameter(pname) << ", "
-      << static_cast<const void*>(params) << ")");
-  GetImageParameterivCHROMIUMHelper(image_id, pname, params);
-  CheckGLError();
-}
-
 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUMHelper(
     GLsizei width,
     GLsizei height,
@@ -4124,20 +4030,15 @@
   // Flush the command stream to ensure ordering in case the newly
   // returned image_id has recently been in use with a different buffer.
   helper_->CommandBufferHelper::Flush();
-
-  // Create new buffer.
-  GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
-      width,
-      height,
-      internalformat == GL_RGBA ? GL_RGBA8_OES : GL_RGB8_OES,
-      usage);
-  if (buffer_id == 0) {
+  int32_t image_id = gpu_control_->CreateGpuMemoryBufferImage(
+      width, height, internalformat, usage);
+  if (image_id < 0) {
     SetGLError(GL_OUT_OF_MEMORY,
                "glCreateGpuMemoryBufferImageCHROMIUM",
-               "out of GPU memory");
+               "image_id < 0");
     return 0;
   }
-  return buffer_id;
+  return image_id;
 }
 
 GLuint GLES2Implementation::CreateGpuMemoryBufferImageCHROMIUM(
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index e3d8fd9..1025a3e 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -24,7 +24,6 @@
 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
 #include "gpu/command_buffer/client/gles2_impl_export.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
 #include "gpu/command_buffer/client/mapped_memory.h"
 #include "gpu/command_buffer/client/query_tracker.h"
 #include "gpu/command_buffer/client/ref_counted.h"
@@ -543,15 +542,11 @@
       GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
       ScopedTransferBufferPtr* buffer);
 
-  GLuint CreateImageCHROMIUMHelper(GLsizei width,
+  GLuint CreateImageCHROMIUMHelper(ClientBuffer buffer,
+                                   GLsizei width,
                                    GLsizei height,
-                                   GLenum internalformat,
-                                   GLenum usage);
+                                   GLenum internalformat);
   void DestroyImageCHROMIUMHelper(GLuint image_id);
-  void* MapImageCHROMIUMHelper(GLuint image_id);
-  void UnmapImageCHROMIUMHelper(GLuint image_id);
-  void GetImageParameterivCHROMIUMHelper(
-      GLuint image_id, GLenum pname, GLint* params);
   GLuint CreateGpuMemoryBufferImageCHROMIUMHelper(GLsizei width,
                                                   GLsizei height,
                                                   GLenum internalformat,
@@ -774,8 +769,6 @@
 
   scoped_ptr<BufferTracker> buffer_tracker_;
 
-  scoped_ptr<GpuMemoryBufferTracker> gpu_memory_buffer_tracker_;
-
   GLES2ImplementationErrorMessageCallback* error_message_callback_;
 
   scoped_ptr<std::string> current_trace_name_;
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 1a36943..5465fc7 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -559,10 +559,6 @@
 
 virtual GLboolean UnmapBufferCHROMIUM(GLuint target) override;
 
-virtual void* MapImageCHROMIUM(GLuint image_id) override;
-
-virtual void UnmapImageCHROMIUM(GLuint image_id) override;
-
 virtual void* MapBufferSubDataCHROMIUM(GLuint target,
                                        GLintptr offset,
                                        GLsizeiptr size,
@@ -604,17 +600,13 @@
 
 virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
 
-virtual GLuint CreateImageCHROMIUM(GLsizei width,
+virtual GLuint CreateImageCHROMIUM(ClientBuffer buffer,
+                                   GLsizei width,
                                    GLsizei height,
-                                   GLenum internalformat,
-                                   GLenum usage) override;
+                                   GLenum internalformat) override;
 
 virtual void DestroyImageCHROMIUM(GLuint image_id) override;
 
-virtual void GetImageParameterivCHROMIUM(GLuint image_id,
-                                         GLenum pname,
-                                         GLint* params) override;
-
 virtual GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width,
                                                   GLsizei height,
                                                   GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index e63ba63..50d7f82 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -964,7 +964,7 @@
   *result = 0;
   helper_->IsBuffer(buffer, GetResultShmId(), GetResultShmOffset());
   WaitForCmd();
-  GLboolean result_value = *result;
+  GLboolean result_value = *result != 0;
   GPU_CLIENT_LOG("returned " << result_value);
   CheckGLError();
   return result_value;
@@ -983,7 +983,7 @@
   *result = 0;
   helper_->IsFramebuffer(framebuffer, GetResultShmId(), GetResultShmOffset());
   WaitForCmd();
-  GLboolean result_value = *result;
+  GLboolean result_value = *result != 0;
   GPU_CLIENT_LOG("returned " << result_value);
   CheckGLError();
   return result_value;
@@ -1001,7 +1001,7 @@
   *result = 0;
   helper_->IsProgram(program, GetResultShmId(), GetResultShmOffset());
   WaitForCmd();
-  GLboolean result_value = *result;
+  GLboolean result_value = *result != 0;
   GPU_CLIENT_LOG("returned " << result_value);
   CheckGLError();
   return result_value;
@@ -1020,7 +1020,7 @@
   *result = 0;
   helper_->IsRenderbuffer(renderbuffer, GetResultShmId(), GetResultShmOffset());
   WaitForCmd();
-  GLboolean result_value = *result;
+  GLboolean result_value = *result != 0;
   GPU_CLIENT_LOG("returned " << result_value);
   CheckGLError();
   return result_value;
@@ -1038,7 +1038,7 @@
   *result = 0;
   helper_->IsShader(shader, GetResultShmId(), GetResultShmOffset());
   WaitForCmd();
-  GLboolean result_value = *result;
+  GLboolean result_value = *result != 0;
   GPU_CLIENT_LOG("returned " << result_value);
   CheckGLError();
   return result_value;
@@ -1056,7 +1056,7 @@
   *result = 0;
   helper_->IsTexture(texture, GetResultShmId(), GetResultShmOffset());
   WaitForCmd();
-  GLboolean result_value = *result;
+  GLboolean result_value = *result != 0;
   GPU_CLIENT_LOG("returned " << result_value);
   CheckGLError();
   return result_value;
@@ -1936,7 +1936,7 @@
   *result = 0;
   helper_->IsVertexArrayOES(array, GetResultShmId(), GetResultShmOffset());
   WaitForCmd();
-  GLboolean result_value = *result;
+  GLboolean result_value = *result != 0;
   GPU_CLIENT_LOG("returned " << result_value);
   CheckGLError();
   return result_value;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 658b7e2..b4e2667 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -3369,9 +3369,9 @@
   };
 
   GLsizei max = std::numeric_limits<GLsizei>::max();
-  EXPECT_CALL(*gpu_control_, CreateGpuMemoryBuffer(max, max, _, _, _))
-      .WillOnce(Return(static_cast<gfx::GpuMemoryBuffer*>(NULL)));
-  gl_->CreateImageCHROMIUM(max, max, 0, GL_IMAGE_MAP_CHROMIUM);
+  EXPECT_CALL(*gpu_control_, CreateGpuMemoryBufferImage(max, max, _, _))
+      .WillOnce(Return(-1));
+  gl_->CreateGpuMemoryBufferImageCHROMIUM(max, max, GL_RGBA, GL_MAP_CHROMIUM);
   // The context should be lost.
   Cmds expected;
   expected.cmd.Init(GL_GUILTY_CONTEXT_RESET_ARB, GL_UNKNOWN_CONTEXT_RESET_ARB);
@@ -3387,9 +3387,9 @@
   };
 
   GLsizei max = std::numeric_limits<GLsizei>::max();
-  EXPECT_CALL(*gpu_control_, CreateGpuMemoryBuffer(max, max, _, _, _))
-      .WillOnce(Return(static_cast<gfx::GpuMemoryBuffer*>(NULL)));
-  gl_->CreateImageCHROMIUM(max, max, 0, GL_IMAGE_MAP_CHROMIUM);
+  EXPECT_CALL(*gpu_control_, CreateGpuMemoryBufferImage(max, max, _, _))
+      .WillOnce(Return(-1));
+  gl_->CreateGpuMemoryBufferImageCHROMIUM(max, max, GL_RGBA, GL_MAP_CHROMIUM);
   // The context should not be lost.
   EXPECT_TRUE(NoCommandsWritten());
 }
diff --git a/gpu/command_buffer/client/gles2_interface.h b/gpu/command_buffer/client/gles2_interface.h
index ca05308..0b0bc51 100644
--- a/gpu/command_buffer/client/gles2_interface.h
+++ b/gpu/command_buffer/client/gles2_interface.h
@@ -9,6 +9,8 @@
 
 #include "base/compiler_specific.h"
 
+extern "C" typedef struct _ClientBuffer* ClientBuffer;
+
 namespace gpu {
 namespace gles2 {
 
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index abfc598..595bde1 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -371,8 +371,6 @@
 virtual GLboolean EnableFeatureCHROMIUM(const char* feature) = 0;
 virtual void* MapBufferCHROMIUM(GLuint target, GLenum access) = 0;
 virtual GLboolean UnmapBufferCHROMIUM(GLuint target) = 0;
-virtual void* MapImageCHROMIUM(GLuint image_id) = 0;
-virtual void UnmapImageCHROMIUM(GLuint image_id) = 0;
 virtual void* MapBufferSubDataCHROMIUM(GLuint target,
                                        GLintptr offset,
                                        GLsizeiptr size,
@@ -403,14 +401,11 @@
                                     GLsizei* size,
                                     void* info) = 0;
 virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) = 0;
-virtual GLuint CreateImageCHROMIUM(GLsizei width,
+virtual GLuint CreateImageCHROMIUM(ClientBuffer buffer,
+                                   GLsizei width,
                                    GLsizei height,
-                                   GLenum internalformat,
-                                   GLenum usage) = 0;
+                                   GLenum internalformat) = 0;
 virtual void DestroyImageCHROMIUM(GLuint image_id) = 0;
-virtual void GetImageParameterivCHROMIUM(GLuint image_id,
-                                         GLenum pname,
-                                         GLint* params) = 0;
 virtual GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width,
                                                   GLsizei height,
                                                   GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index f059cad..b021b56 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -402,8 +402,6 @@
 virtual GLboolean EnableFeatureCHROMIUM(const char* feature) override;
 virtual void* MapBufferCHROMIUM(GLuint target, GLenum access) override;
 virtual GLboolean UnmapBufferCHROMIUM(GLuint target) override;
-virtual void* MapImageCHROMIUM(GLuint image_id) override;
-virtual void UnmapImageCHROMIUM(GLuint image_id) override;
 virtual void* MapBufferSubDataCHROMIUM(GLuint target,
                                        GLintptr offset,
                                        GLsizeiptr size,
@@ -434,14 +432,11 @@
                                     GLsizei* size,
                                     void* info) override;
 virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
-virtual GLuint CreateImageCHROMIUM(GLsizei width,
+virtual GLuint CreateImageCHROMIUM(ClientBuffer buffer,
+                                   GLsizei width,
                                    GLsizei height,
-                                   GLenum internalformat,
-                                   GLenum usage) override;
+                                   GLenum internalformat) override;
 virtual void DestroyImageCHROMIUM(GLuint image_id) override;
-virtual void GetImageParameterivCHROMIUM(GLuint image_id,
-                                         GLenum pname,
-                                         GLint* params) override;
 virtual GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width,
                                                   GLsizei height,
                                                   GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index cde303f..0936086 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -662,11 +662,6 @@
 GLboolean GLES2InterfaceStub::UnmapBufferCHROMIUM(GLuint /* target */) {
   return 0;
 }
-void* GLES2InterfaceStub::MapImageCHROMIUM(GLuint /* image_id */) {
-  return 0;
-}
-void GLES2InterfaceStub::UnmapImageCHROMIUM(GLuint /* image_id */) {
-}
 void* GLES2InterfaceStub::MapBufferSubDataCHROMIUM(GLuint /* target */,
                                                    GLintptr /* offset */,
                                                    GLsizeiptr /* size */,
@@ -712,18 +707,14 @@
 GLuint GLES2InterfaceStub::CreateStreamTextureCHROMIUM(GLuint /* texture */) {
   return 0;
 }
-GLuint GLES2InterfaceStub::CreateImageCHROMIUM(GLsizei /* width */,
+GLuint GLES2InterfaceStub::CreateImageCHROMIUM(ClientBuffer /* buffer */,
+                                               GLsizei /* width */,
                                                GLsizei /* height */,
-                                               GLenum /* internalformat */,
-                                               GLenum /* usage */) {
+                                               GLenum /* internalformat */) {
   return 0;
 }
 void GLES2InterfaceStub::DestroyImageCHROMIUM(GLuint /* image_id */) {
 }
-void GLES2InterfaceStub::GetImageParameterivCHROMIUM(GLuint /* image_id */,
-                                                     GLenum /* pname */,
-                                                     GLint* /* params */) {
-}
 GLuint GLES2InterfaceStub::CreateGpuMemoryBufferImageCHROMIUM(
     GLsizei /* width */,
     GLsizei /* height */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 1e7bc8f..aa0c96f 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -402,8 +402,6 @@
 virtual GLboolean EnableFeatureCHROMIUM(const char* feature) override;
 virtual void* MapBufferCHROMIUM(GLuint target, GLenum access) override;
 virtual GLboolean UnmapBufferCHROMIUM(GLuint target) override;
-virtual void* MapImageCHROMIUM(GLuint image_id) override;
-virtual void UnmapImageCHROMIUM(GLuint image_id) override;
 virtual void* MapBufferSubDataCHROMIUM(GLuint target,
                                        GLintptr offset,
                                        GLsizeiptr size,
@@ -434,14 +432,11 @@
                                     GLsizei* size,
                                     void* info) override;
 virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
-virtual GLuint CreateImageCHROMIUM(GLsizei width,
+virtual GLuint CreateImageCHROMIUM(ClientBuffer buffer,
+                                   GLsizei width,
                                    GLsizei height,
-                                   GLenum internalformat,
-                                   GLenum usage) override;
+                                   GLenum internalformat) override;
 virtual void DestroyImageCHROMIUM(GLuint image_id) override;
-virtual void GetImageParameterivCHROMIUM(GLuint image_id,
-                                         GLenum pname,
-                                         GLint* params) override;
 virtual GLuint CreateGpuMemoryBufferImageCHROMIUM(GLsizei width,
                                                   GLsizei height,
                                                   GLenum internalformat,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index 4495967..d1b5fce 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1156,16 +1156,6 @@
   return gl_->UnmapBufferCHROMIUM(target);
 }
 
-void* GLES2TraceImplementation::MapImageCHROMIUM(GLuint image_id) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::MapImageCHROMIUM");
-  return gl_->MapImageCHROMIUM(image_id);
-}
-
-void GLES2TraceImplementation::UnmapImageCHROMIUM(GLuint image_id) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UnmapImageCHROMIUM");
-  gl_->UnmapImageCHROMIUM(image_id);
-}
-
 void* GLES2TraceImplementation::MapBufferSubDataCHROMIUM(GLuint target,
                                                          GLintptr offset,
                                                          GLsizeiptr size,
@@ -1247,12 +1237,12 @@
   return gl_->CreateStreamTextureCHROMIUM(texture);
 }
 
-GLuint GLES2TraceImplementation::CreateImageCHROMIUM(GLsizei width,
+GLuint GLES2TraceImplementation::CreateImageCHROMIUM(ClientBuffer buffer,
+                                                     GLsizei width,
                                                      GLsizei height,
-                                                     GLenum internalformat,
-                                                     GLenum usage) {
+                                                     GLenum internalformat) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CreateImageCHROMIUM");
-  return gl_->CreateImageCHROMIUM(width, height, internalformat, usage);
+  return gl_->CreateImageCHROMIUM(buffer, width, height, internalformat);
 }
 
 void GLES2TraceImplementation::DestroyImageCHROMIUM(GLuint image_id) {
@@ -1260,14 +1250,6 @@
   gl_->DestroyImageCHROMIUM(image_id);
 }
 
-void GLES2TraceImplementation::GetImageParameterivCHROMIUM(GLuint image_id,
-                                                           GLenum pname,
-                                                           GLint* params) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
-                                "GLES2Trace::GetImageParameterivCHROMIUM");
-  gl_->GetImageParameterivCHROMIUM(image_id, pname, params);
-}
-
 GLuint GLES2TraceImplementation::CreateGpuMemoryBufferImageCHROMIUM(
     GLsizei width,
     GLsizei height,
diff --git a/gpu/command_buffer/client/gpu_control.h b/gpu/command_buffer/client/gpu_control.h
index b28757c..a56bd51 100644
--- a/gpu/command_buffer/client/gpu_control.h
+++ b/gpu/command_buffer/client/gpu_control.h
@@ -15,6 +15,8 @@
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/gpu_export.h"
 
+extern "C" typedef struct _ClientBuffer* ClientBuffer;
+
 namespace gfx {
 class GpuMemoryBuffer;
 }
@@ -29,17 +31,22 @@
 
   virtual Capabilities GetCapabilities() = 0;
 
-  // 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,
-      unsigned usage,
-      int32_t* id) = 0;
+  // Create an image for a client buffer with the given dimensions and
+  // format. Returns its ID or -1 on error.
+  virtual int32_t CreateImage(ClientBuffer buffer,
+                              size_t width,
+                              size_t height,
+                              unsigned internalformat) = 0;
 
-  // Destroy a gpu memory buffer. The ID must be positive.
-  virtual void DestroyGpuMemoryBuffer(int32_t id) = 0;
+  // Destroy an image. The ID must be positive.
+  virtual void DestroyImage(int32_t id) = 0;
+
+  // Create a gpu memory buffer backed image with the given dimensions and
+  // format for |usage|. Returns its ID or -1 on error.
+  virtual int32_t CreateGpuMemoryBufferImage(size_t width,
+                                             size_t height,
+                                             unsigned internalformat,
+                                             unsigned usage) = 0;
 
   // Inserts a sync point, returning its ID. Sync point IDs are global and can
   // be used for cross-context synchronization.
diff --git a/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc b/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
deleted file mode 100644
index 9ffe0e3..0000000
--- a/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 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/client/gpu_memory_buffer_tracker.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/gpu_control.h"
-
-namespace gpu {
-namespace gles2 {
-
-GpuMemoryBufferTracker::GpuMemoryBufferTracker(GpuControl* gpu_control)
-    : gpu_control_(gpu_control) {
-}
-
-GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
-  while (!buffers_.empty()) {
-    RemoveBuffer(buffers_.begin()->first);
-  }
-}
-
-int32 GpuMemoryBufferTracker::CreateBuffer(size_t width,
-                                           size_t height,
-                                           int32 internalformat,
-                                           int32 usage) {
-  int32 image_id = 0;
-  DCHECK(gpu_control_);
-  gfx::GpuMemoryBuffer* buffer = gpu_control_->CreateGpuMemoryBuffer(
-      width, height, internalformat, usage, &image_id);
-  if (!buffer)
-    return 0;
-
-  std::pair<BufferMap::iterator, bool> result =
-      buffers_.insert(std::make_pair(image_id, buffer));
-  DCHECK(result.second);
-
-  return 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(int32 image_id) {
-  BufferMap::iterator buffer_it = buffers_.find(image_id);
-  if (buffer_it != buffers_.end())
-    buffers_.erase(buffer_it);
-  DCHECK(gpu_control_);
-  gpu_control_->DestroyGpuMemoryBuffer(image_id);
-}
-
-}  // namespace gles2
-}  // namespace gpu
diff --git a/gpu/command_buffer/client/gpu_memory_buffer_tracker.h b/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
deleted file mode 100644
index 25ec949..0000000
--- a/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 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_GPU_MEMORY_BUFFER_TRACKER_H_
-#define GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
-
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "gles2_impl_export.h"
-
-namespace gfx {
-class GpuMemoryBuffer;
-}
-
-namespace gpu {
-class GpuControl;
-
-namespace gles2 {
-
-// Tracks GPU memory buffer objects on the client side.
-class GLES2_IMPL_EXPORT GpuMemoryBufferTracker {
- public:
-  explicit GpuMemoryBufferTracker(GpuControl* gpu_control);
-  virtual ~GpuMemoryBufferTracker();
-
-  int32 CreateBuffer(size_t width,
-                     size_t height,
-                     int32 internalformat,
-                     int32 usage);
-  gfx::GpuMemoryBuffer* GetBuffer(int32 image_id);
-  void RemoveBuffer(int32 image_id);
-
- private:
-  typedef base::hash_map<int32, gfx::GpuMemoryBuffer*> BufferMap;
-  BufferMap buffers_;
-  GpuControl* gpu_control_;
-
-  DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferTracker);
-};
-
-}  // namespace gles2
-}  // namespace gpu
-
-#endif  // GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 5964cd8..49cb433 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -175,9 +175,6 @@
 GL_APICALL GLboolean    GL_APIENTRY glEnableFeatureCHROMIUM (const char* feature);
 GL_APICALL void*        GL_APIENTRY glMapBufferCHROMIUM (GLuint target, GLenum access);
 GL_APICALL GLboolean    GL_APIENTRY glUnmapBufferCHROMIUM (GLuint target);
-GL_APICALL void*        GL_APIENTRY glMapImageCHROMIUM (GLuint image_id);
-GL_APICALL void         GL_APIENTRY glUnmapImageCHROMIUM (GLuint image_id);
-
 GL_APICALL void*        GL_APIENTRY glMapBufferSubDataCHROMIUM (GLuint target, GLintptrNotNegative offset, GLsizeiptr size, GLenum access);
 GL_APICALL void         GL_APIENTRY glUnmapBufferSubDataCHROMIUM (const void* mem);
 GL_APICALL void*        GL_APIENTRY glMapTexSubImage2DCHROMIUM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLenum access);
@@ -189,9 +186,8 @@
 GL_APICALL void         GL_APIENTRY glGetMultipleIntegervCHROMIUM (const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
 GL_APICALL void         GL_APIENTRY glGetProgramInfoCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
 GL_APICALL GLuint       GL_APIENTRY glCreateStreamTextureCHROMIUM (GLuint texture);
-GL_APICALL GLuint       GL_APIENTRY glCreateImageCHROMIUM (GLsizei width, GLsizei height, GLenum internalformat, GLenum usage);
+GL_APICALL GLuint       GL_APIENTRY glCreateImageCHROMIUM (ClientBuffer buffer, GLsizei width, GLsizei height, GLenum internalformat);
 GL_APICALL void         GL_APIENTRY glDestroyImageCHROMIUM (GLuint image_id);
-GL_APICALL void         GL_APIENTRY glGetImageParameterivCHROMIUM (GLuint image_id, GLenum pname, GLint* params);
 GL_APICALL GLuint       GL_APIENTRY glCreateGpuMemoryBufferImageCHROMIUM (GLsizei width, GLsizei height, GLenum internalformat, GLenum usage);
 GL_APICALL void         GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLidShader shader, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* source);
 GL_APICALL void         GL_APIENTRY glPostSubBufferCHROMIUM (GLint x, GLint y, GLint width, GLint height);
diff --git a/gpu/command_buffer/common/capabilities.cc b/gpu/command_buffer/common/capabilities.cc
index 74b2423..f51071a 100644
--- a/gpu/command_buffer/common/capabilities.cc
+++ b/gpu/command_buffer/common/capabilities.cc
@@ -19,7 +19,8 @@
       discard_framebuffer(false),
       sync_query(false),
       image(false),
-      future_sync_points(false) {
+      future_sync_points(false),
+      blend_minmax(false) {
 }
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index cb0246f..df97d1f 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -23,6 +23,7 @@
   bool sync_query;
   bool image;
   bool future_sync_points;
+  bool blend_minmax;
 
   Capabilities();
 };
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 3b5097c..41db0b8 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -232,6 +232,10 @@
     //    GL_EXT_multisampled_render_to_texture
     case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT:
       return 1;
+    // -- glGetFramebufferAttachmentParameteriv with
+    //    GL_EXT_sRGB
+    case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
+      return 1;
 
     // -- glGetProgramiv
     case GL_DELETE_STATUS:
@@ -352,11 +356,13 @@
 
     switch (format) {
     case GL_RGB:
+    case GL_SRGB_EXT:
        return 3;
     case GL_LUMINANCE_ALPHA:
        return 2;
     case GL_RGBA:
     case GL_BGRA_EXT:
+    case GL_SRGB_ALPHA_EXT:
        return 4;
     case GL_ALPHA:
     case GL_LUMINANCE:
@@ -670,6 +676,7 @@
     case GL_RGB565:
     case GL_RGB16F_EXT:
     case GL_RGB32F_EXT:
+    case GL_SRGB_EXT:
       return kRGB;
     case GL_BGRA_EXT:
     case GL_BGRA8_EXT:
@@ -679,6 +686,8 @@
     case GL_RGBA8_OES:
     case GL_RGBA4:
     case GL_RGB5_A1:
+    case GL_SRGB_ALPHA_EXT:
+    case GL_SRGB8_ALPHA8_EXT:
       return kRGBA;
     case GL_DEPTH_COMPONENT32_OES:
     case GL_DEPTH_COMPONENT24_OES:
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index c5bbc54..20b4493 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -129,10 +129,6 @@
      "GL_LINES",
     },
     {
-     0x78F0,
-     "GL_IMAGE_ROWBYTES_CHROMIUM",
-    },
-    {
      0x88B8,
      "GL_READ_ONLY",
     },
@@ -1314,7 +1310,7 @@
     },
     {
      0x78F1,
-     "GL_IMAGE_MAP_CHROMIUM",
+     "GL_MAP_CHROMIUM",
     },
     {
      0x00080000,
@@ -1334,7 +1330,7 @@
     },
     {
      0x78F2,
-     "GL_IMAGE_SCANOUT_CHROMIUM",
+     "GL_SCANOUT_CHROMIUM",
     },
     {
      0x93C7,
diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager.h b/gpu/command_buffer/service/async_pixel_transfer_manager.h
index 63b30c6..66b8bf7 100644
--- a/gpu/command_buffer/service/async_pixel_transfer_manager.h
+++ b/gpu/command_buffer/service/async_pixel_transfer_manager.h
@@ -15,17 +15,6 @@
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/gpu_export.h"
 
-#if defined(COMPILER_GCC)
-namespace BASE_HASH_NAMESPACE {
-template <>
-  struct hash<gpu::gles2::TextureRef*> {
-  size_t operator()(gpu::gles2::TextureRef* ptr) const {
-    return hash<size_t>()(reinterpret_cast<size_t>(ptr));
-  }
-};
-}  // namespace BASE_HASH_NAMESPACE
-#endif  // COMPILER
-
 namespace gfx {
 class GLContext;
 }
diff --git a/gpu/command_buffer/service/disk_cache_proto.proto b/gpu/command_buffer/service/disk_cache_proto.proto
index 5a55943..ab3bb57 100644
--- a/gpu/command_buffer/service/disk_cache_proto.proto
+++ b/gpu/command_buffer/service/disk_cache_proto.proto
@@ -1,24 +1,41 @@
 option optimize_for = LITE_RUNTIME;
 
-message ShaderInfoProto {
-  optional int32 type = 1;
-  optional int32 size = 2;
+message ShaderVariableProto {
+  optional uint32 type = 1;
+  optional uint32 precision = 2;
   optional string name = 3;
-  optional string key = 4;
-  optional int32 precision = 5;
-  optional int32 static_use = 6;  
+  optional string mapped_name = 4;
+  optional uint32 array_size = 5;
+  optional bool static_use = 6;
+  repeated ShaderVariableProto fields = 7;
+  optional string struct_name = 8;
+}
+
+message ShaderAttributeProto {
+  optional ShaderVariableProto basic = 1;
+  optional int32 location = 2;
+}
+
+message ShaderUniformProto {
+  optional ShaderVariableProto basic = 1;
+}
+
+message ShaderVaryingProto {
+  optional ShaderVariableProto basic = 1;
+  optional int32 interpolation = 2;
+  optional bool is_invariant = 3;
 }
 
 message ShaderProto {
   optional bytes sha = 1;
-  repeated ShaderInfoProto attribs = 2;
-  repeated ShaderInfoProto uniforms = 3;
-  repeated ShaderInfoProto varyings = 4;
+  repeated ShaderAttributeProto attribs = 2;
+  repeated ShaderUniformProto uniforms = 3;
+  repeated ShaderVaryingProto varyings = 4;
 }
 
 message GpuProgramProto {
   optional bytes sha = 1;
-  optional int32 format = 2;
+  optional uint32 format = 2;
   optional bytes program = 3;
 
   optional ShaderProto vertex_shader = 4;
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index e853d9b..bda7a82 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -132,6 +132,7 @@
       enable_shader_name_hashing(false),
       enable_samplers(false),
       ext_draw_buffers(false),
+      nv_draw_buffers(false),
       ext_frag_depth(false),
       ext_shader_texture_lod(false),
       use_async_readpixels(false),
@@ -142,7 +143,8 @@
       is_swiftshader(false),
       angle_texture_usage(false),
       ext_texture_storage(false),
-      chromium_path_rendering(false) {
+      chromium_path_rendering(false),
+      ext_blend_minmax(false) {
 }
 
 FeatureInfo::Workarounds::Workarounds() :
@@ -391,6 +393,20 @@
     validators_.index_type.AddValue(GL_UNSIGNED_INT);
   }
 
+  if (is_es3 || extensions.Contains("GL_EXT_sRGB") ||
+      gfx::HasDesktopGLFeatures()) {
+    AddExtensionString("GL_EXT_sRGB");
+    texture_format_validators_[GL_SRGB_EXT].AddValue(GL_UNSIGNED_BYTE);
+    texture_format_validators_[GL_SRGB_ALPHA_EXT].AddValue(GL_UNSIGNED_BYTE);
+    validators_.texture_internal_format.AddValue(GL_SRGB_EXT);
+    validators_.texture_internal_format.AddValue(GL_SRGB_ALPHA_EXT);
+    validators_.texture_format.AddValue(GL_SRGB_EXT);
+    validators_.texture_format.AddValue(GL_SRGB_ALPHA_EXT);
+    validators_.render_buffer_format.AddValue(GL_SRGB8_ALPHA8_EXT);
+    validators_.frame_buffer_parameter.AddValue(
+        GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT);
+  }
+
   bool enable_texture_format_bgra8888 = false;
   bool enable_read_format_bgra = false;
   bool enable_render_buffer_bgra = false;
@@ -760,12 +776,25 @@
     validators_.vertex_attribute.AddValue(GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
   }
 
+  bool vendor_agnostic_draw_buffers =
+      extensions.Contains("GL_ARB_draw_buffers") ||
+      extensions.Contains("GL_EXT_draw_buffers");
   if (!workarounds_.disable_ext_draw_buffers &&
-      (extensions.Contains("GL_ARB_draw_buffers") ||
-       extensions.Contains("GL_EXT_draw_buffers"))) {
+      (vendor_agnostic_draw_buffers ||
+       (extensions.Contains("GL_NV_draw_buffers") && is_es3))) {
     AddExtensionString("GL_EXT_draw_buffers");
     feature_flags_.ext_draw_buffers = true;
 
+    // This flag is set to enable emulation of EXT_draw_buffers when we're
+    // running on GLES 3.0+, NV_draw_buffers extension is supported and
+    // glDrawBuffers from GLES 3.0 core has been bound. It toggles using the
+    // NV_draw_buffers extension directive instead of EXT_draw_buffers extension
+    // directive in ESSL 100 shaders translated by ANGLE, enabling them to write
+    // into multiple gl_FragData values, which is not by default possible in
+    // ESSL 100 with core GLES 3.0. For more information, see the
+    // NV_draw_buffers specification.
+    feature_flags_.nv_draw_buffers = !vendor_agnostic_draw_buffers;
+
     GLint max_color_attachments = 0;
     glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &max_color_attachments);
     for (GLenum i = GL_COLOR_ATTACHMENT1_EXT;
@@ -789,6 +818,7 @@
 
   if (is_es3 || extensions.Contains("GL_EXT_blend_minmax") ||
       gfx::HasDesktopGLFeatures()) {
+    feature_flags_.ext_blend_minmax = true;
     AddExtensionString("GL_EXT_blend_minmax");
     validators_.equation.AddValue(GL_MIN_EXT);
     validators_.equation.AddValue(GL_MAX_EXT);
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 740b833..a30581a 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -59,6 +59,7 @@
     bool enable_shader_name_hashing;
     bool enable_samplers;
     bool ext_draw_buffers;
+    bool nv_draw_buffers;
     bool ext_frag_depth;
     bool ext_shader_texture_lod;
     bool use_async_readpixels;
@@ -70,6 +71,7 @@
     bool angle_texture_usage;
     bool ext_texture_storage;
     bool chromium_path_rendering;
+    bool ext_blend_minmax;
   };
 
   struct Workarounds {
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index 106e183..004eeee 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -123,6 +123,8 @@
   EXPECT_FALSE(info_->feature_flags().native_vertex_array_object);
   EXPECT_FALSE(info_->feature_flags().map_buffer_range);
   EXPECT_FALSE(info_->feature_flags().use_async_readpixels);
+  EXPECT_FALSE(info_->feature_flags().ext_draw_buffers);
+  EXPECT_FALSE(info_->feature_flags().nv_draw_buffers);
   EXPECT_FALSE(info_->feature_flags().ext_discard_framebuffer);
   EXPECT_FALSE(info_->feature_flags().angle_depth_texture);
   EXPECT_FALSE(info_->feature_flags().is_angle);
@@ -251,6 +253,8 @@
               Not(HasSubstr("GL_AMD_compressed_ATC_texture")));
   EXPECT_THAT(info_->extensions(),
               Not(HasSubstr("GL_IMG_texture_compression_pvrtc")));
+  EXPECT_THAT(info_->extensions(),
+              Not(HasSubstr("GL_EXT_sRGB")));
   EXPECT_FALSE(info_->feature_flags().npot_ok);
   EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
       GL_COMPRESSED_RGB_S3TC_DXT1_EXT));
@@ -320,6 +324,22 @@
   EXPECT_FALSE(info_->validators()->equation.IsValid(GL_MIN_EXT));
   EXPECT_FALSE(info_->validators()->equation.IsValid(GL_MAX_EXT));
   EXPECT_FALSE(info_->feature_flags().chromium_sync_query);
+  EXPECT_FALSE(info_->GetTextureFormatValidator(GL_SRGB_EXT).IsValid(
+      GL_UNSIGNED_BYTE));
+  EXPECT_FALSE(info_->GetTextureFormatValidator(GL_SRGB_ALPHA_EXT).IsValid(
+      GL_UNSIGNED_BYTE));
+  EXPECT_FALSE(info_->validators()->texture_format.IsValid(
+      GL_SRGB_EXT));
+  EXPECT_FALSE(info_->validators()->texture_format.IsValid(
+      GL_SRGB_ALPHA_EXT));
+  EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+      GL_SRGB_EXT));
+  EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+      GL_SRGB_ALPHA_EXT));
+  EXPECT_FALSE(info_->validators()->render_buffer_format.IsValid(
+      GL_SRGB8_ALPHA8_EXT));
+  EXPECT_FALSE(info_->validators()->frame_buffer_parameter.IsValid(
+      GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT));
 }
 
 TEST_F(FeatureInfoTest, InitializeWithANGLE) {
@@ -433,6 +453,28 @@
       GL_BGRA8_EXT));
 }
 
+TEST_F(FeatureInfoTest, InitializeEXT_sRGB) {
+  SetupInitExpectations("GL_EXT_sRGB");
+  EXPECT_THAT(info_->extensions(),
+              HasSubstr("GL_EXT_sRGB"));
+  EXPECT_TRUE(info_->GetTextureFormatValidator(GL_SRGB_EXT).IsValid(
+      GL_UNSIGNED_BYTE));
+  EXPECT_TRUE(info_->GetTextureFormatValidator(GL_SRGB_ALPHA_EXT).IsValid(
+      GL_UNSIGNED_BYTE));
+  EXPECT_TRUE(info_->validators()->texture_format.IsValid(
+      GL_SRGB_EXT));
+  EXPECT_TRUE(info_->validators()->texture_format.IsValid(
+      GL_SRGB_ALPHA_EXT));
+  EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+      GL_SRGB_EXT));
+  EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+      GL_SRGB_ALPHA_EXT));
+  EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(
+      GL_SRGB8_ALPHA8_EXT));
+  EXPECT_TRUE(info_->validators()->frame_buffer_parameter.IsValid(
+      GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT));
+}
+
 TEST_F(FeatureInfoTest, InitializeEXT_texture_storage) {
   SetupInitExpectations("GL_EXT_texture_storage");
   EXPECT_TRUE(info_->feature_flags().ext_texture_storage);
@@ -1254,6 +1296,19 @@
   EXPECT_TRUE(gfx::GLFence::IsSupported());
 }
 
+TEST_F(FeatureInfoTest, InitializeWithNVDrawBuffers) {
+  SetupInitExpectationsWithGLVersion("GL_NV_draw_buffers", "", "OpenGL ES 3.0");
+  EXPECT_TRUE(info_->feature_flags().nv_draw_buffers);
+  EXPECT_TRUE(info_->feature_flags().ext_draw_buffers);
+}
+
+TEST_F(FeatureInfoTest, InitializeWithPreferredEXTDrawBuffers) {
+  SetupInitExpectationsWithGLVersion(
+      "GL_NV_draw_buffers GL_EXT_draw_buffers", "", "OpenGL ES 3.0");
+  EXPECT_FALSE(info_->feature_flags().nv_draw_buffers);
+  EXPECT_TRUE(info_->feature_flags().ext_draw_buffers);
+}
+
 TEST_F(FeatureInfoTest, ARBSyncDisabled) {
   CommandLine command_line(0, NULL);
   command_line.AppendSwitchASCII(
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc
index 4448ac8..60f3ac9 100644
--- a/gpu/command_buffer/service/framebuffer_manager.cc
+++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -126,6 +126,10 @@
 
   virtual void OnWillRenderTo() const override {}
   virtual void OnDidRenderTo() const override {}
+  virtual bool FormsFeedbackLoop(
+      TextureRef* /* texture */, GLint /*level */) const override {
+    return false;
+  }
 
  protected:
   virtual ~RenderbufferAttachment() { }
@@ -264,6 +268,11 @@
     texture_ref_->texture()->OnDidModifyPixels();
   }
 
+  virtual bool FormsFeedbackLoop(
+      TextureRef* texture, GLint level) const override {
+    return texture == texture_ref_.get() && level == level_;
+  }
+
  protected:
   virtual ~TextureAttachment() {}
 
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index 96bf7fe..78c11ad 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -52,6 +52,7 @@
         TextureManager* texture_manager, std::string* signature) const = 0;
     virtual void OnWillRenderTo() const = 0;
     virtual void OnDidRenderTo() const = 0;
+    virtual bool FormsFeedbackLoop(TextureRef* texture, GLint level) const = 0;
 
    protected:
     friend class base::RefCounted<Attachment>;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 65587ec..20c4da8 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1181,6 +1181,10 @@
   // attached. Generates GL error if not.
   bool CheckBoundReadFramebufferColorAttachment(const char* func_name);
 
+  // Check that the currently bound read framebuffer's color image
+  // isn't the target texture of the glCopyTex{Sub}Image2D.
+  bool FormsTextureCopyingFeedbackLoop(TextureRef* texture, GLint level);
+
   // Check if a framebuffer meets our requirements.
   bool CheckFramebufferValid(
       Framebuffer* framebuffer,
@@ -2746,6 +2750,7 @@
   caps.post_sub_buffer = supports_post_sub_buffer_;
   caps.image = true;
 
+  caps.blend_minmax = feature_info_->feature_flags().ext_blend_minmax;
   return caps;
 }
 
@@ -2792,6 +2797,8 @@
     if (!draw_buffers_explicitly_enabled_)
       resources.MaxDrawBuffers = 1;
     resources.EXT_shader_texture_lod = shader_texture_lod_explicitly_enabled_;
+    resources.NV_draw_buffers =
+        draw_buffers_explicitly_enabled_ && features().nv_draw_buffers;
   } else {
     resources.OES_standard_derivatives =
         features().oes_standard_derivatives ? 1 : 0;
@@ -2805,6 +2812,8 @@
         features().ext_frag_depth ? 1 : 0;
     resources.EXT_shader_texture_lod =
         features().ext_shader_texture_lod ? 1 : 0;
+    resources.NV_draw_buffers =
+        features().nv_draw_buffers ? 1 : 0;
   }
 
   ShShaderSpec shader_spec = force_webgl_glsl_validation_ ? SH_WEBGL_SPEC
@@ -3227,6 +3236,20 @@
   return true;
 }
 
+bool GLES2DecoderImpl::FormsTextureCopyingFeedbackLoop(
+    TextureRef* texture, GLint level) {
+  Framebuffer* framebuffer = features().chromium_framebuffer_multisample ?
+      framebuffer_state_.bound_read_framebuffer.get() :
+      framebuffer_state_.bound_draw_framebuffer.get();
+  if (!framebuffer)
+    return false;
+  const Framebuffer::Attachment* attachment = framebuffer->GetAttachment(
+      GL_COLOR_ATTACHMENT0);
+  if (!attachment)
+    return false;
+  return attachment->FormsFeedbackLoop(texture, level);
+}
+
 gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() {
   Framebuffer* framebuffer =
       GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER_EXT);
@@ -4859,7 +4882,13 @@
   if (!program) {
     return;
   }
+  // At this point, the program's shaders may not be translated yet,
+  // therefore, we may not find the hashed attribute name.
+  // glBindAttribLocation call with original name is useless.
+  // So instead, we should simply cache the binding, and then call
+  // Program::ExecuteBindAttribLocationCalls() right before link.
   program->SetAttribLocationBinding(name, static_cast<GLint>(index));
+  // TODO(zmo): Get rid of the following glBindAttribLocation call.
   glBindAttribLocation(program->service_id(), index, name);
 }
 
@@ -8590,6 +8619,13 @@
     return;
   }
 
+  if (FormsTextureCopyingFeedbackLoop(texture_ref, level)) {
+    LOCAL_SET_GL_ERROR(
+        GL_INVALID_OPERATION,
+        "glCopyTexImage2D", "source and destination textures are the same");
+    return;
+  }
+
   if (!CheckBoundFramebuffersValid("glCopyTexImage2D")) {
     return;
   }
@@ -8708,6 +8744,13 @@
     return;
   }
 
+  if (FormsTextureCopyingFeedbackLoop(texture_ref, level)) {
+    LOCAL_SET_GL_ERROR(
+        GL_INVALID_OPERATION,
+        "glCopyTexSubImage2D", "source and destination textures are the same");
+    return;
+  }
+
   if (!CheckBoundFramebuffersValid("glCopyTexSubImage2D")) {
     return;
   }
@@ -10084,6 +10127,8 @@
       return GL_LUMINANCE_ALPHA;
     case GL_BGRA8_EXT:
       return GL_BGRA_EXT;
+    case GL_SRGB8_ALPHA8_EXT:
+      return GL_SRGB_ALPHA_EXT;
     default:
       return GL_NONE;
   }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
index 32ba98d..ce8f307 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -2022,7 +2022,15 @@
       .RetiresOnSaturation();
   CopyTexImage2D cmd;
   cmd.Init(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 1, 1);
+  // Unbind fbo and bind again after CopyTexImage2D tp avoid feedback loops.
+  if (bound_fbo) {
+    DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0);
+  }
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  if (bound_fbo) {
+    DoBindFramebuffer(
+        GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+  }
   EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer));
 
   // Test deleting texture marks fbo as not complete.
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 707b9ef..1d0ce6a 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -609,18 +609,25 @@
   return capabilities_;
 }
 
-gfx::GpuMemoryBuffer* InProcessCommandBuffer::CreateGpuMemoryBuffer(
+int32 InProcessCommandBuffer::CreateImage(ClientBuffer buffer,
+                                          size_t width,
+                                          size_t height,
+                                          unsigned internalformat) {
+  NOTREACHED();
+  return -1;
+}
+
+void InProcessCommandBuffer::DestroyImage(int32 id) {
+  NOTREACHED();
+}
+
+int32 InProcessCommandBuffer::CreateGpuMemoryBufferImage(
     size_t width,
     size_t height,
     unsigned internalformat,
-    unsigned usage,
-    int32* id) {
+    unsigned usage) {
   NOTREACHED();
-  return NULL;
-}
-
-void InProcessCommandBuffer::DestroyGpuMemoryBuffer(int32 id) {
-  NOTREACHED();
+  return -1;
 }
 
 uint32 InProcessCommandBuffer::InsertSyncPoint() {
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index e91d6f6..65cf1ec 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -94,12 +94,15 @@
 
   // GpuControl implementation:
   virtual gpu::Capabilities GetCapabilities() override;
-  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(size_t width,
-                                                      size_t height,
-                                                      unsigned internalformat,
-                                                      unsigned usage,
-                                                      int32* id) override;
-  virtual void DestroyGpuMemoryBuffer(int32 id) override;
+  virtual int32 CreateImage(ClientBuffer buffer,
+                            size_t width,
+                            size_t height,
+                            unsigned internalformat) override;
+  virtual void DestroyImage(int32 id) override;
+  virtual int32 CreateGpuMemoryBufferImage(size_t width,
+                                           size_t height,
+                                           unsigned internalformat,
+                                           unsigned usage) override;
   virtual uint32 InsertSyncPoint() override;
   virtual uint32 InsertFutureSyncPoint() override;
   virtual void RetireSyncPoint(uint32 sync_point) override;
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index 87378aa..86fffd3 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -45,47 +45,96 @@
   VARYING_MAP
 };
 
-void StoreShaderInfo(ShaderMapType type, ShaderProto *proto,
-                     const ShaderTranslator::VariableMap& map) {
-  ShaderTranslator::VariableMap::const_iterator iter;
-  for (iter = map.begin(); iter != map.end(); ++iter) {
-    ShaderInfoProto* info = NULL;
-    switch (type) {
-      case UNIFORM_MAP:
-        info = proto->add_uniforms();
-        break;
-      case ATTRIB_MAP:
-        info = proto->add_attribs();
-        break;
-      case VARYING_MAP:
-        info = proto->add_varyings();
-        break;
-      default: NOTREACHED();
-    }
-
-    info->set_key(iter->first);
-    info->set_type(iter->second.type);
-    info->set_size(iter->second.size);
-    info->set_precision(iter->second.precision);
-    info->set_static_use(iter->second.static_use);
-    info->set_name(iter->second.name);
+void FillShaderVariableProto(
+    ShaderVariableProto* proto, const sh::ShaderVariable& variable) {
+  proto->set_type(variable.type);
+  proto->set_precision(variable.precision);
+  proto->set_name(variable.name);
+  proto->set_mapped_name(variable.mappedName);
+  proto->set_array_size(variable.arraySize);
+  proto->set_static_use(variable.staticUse);
+  for (size_t ii = 0; ii < variable.fields.size(); ++ii) {
+    ShaderVariableProto* field = proto->add_fields();
+    FillShaderVariableProto(field, variable.fields[ii]);
   }
+  proto->set_struct_name(variable.structName);
 }
 
-void RetrieveShaderInfo(const ShaderInfoProto& proto,
-                        ShaderTranslator::VariableMap* map) {
-  ShaderTranslator::VariableInfo info(
-      proto.type(), proto.size(), proto.precision(),
-      proto.static_use(), proto.name());
-  (*map)[proto.key()] = info;
+void FillShaderAttributeProto(
+    ShaderAttributeProto* proto, const sh::Attribute& attrib) {
+  FillShaderVariableProto(proto->mutable_basic(), attrib);
+  proto->set_location(attrib.location);
+}
+
+void FillShaderUniformProto(
+    ShaderUniformProto* proto, const sh::Uniform& uniform) {
+  FillShaderVariableProto(proto->mutable_basic(), uniform);
+}
+
+void FillShaderVaryingProto(
+    ShaderVaryingProto* proto, const sh::Varying& varying) {
+  FillShaderVariableProto(proto->mutable_basic(), varying);
+  proto->set_interpolation(varying.interpolation);
+  proto->set_is_invariant(varying.isInvariant);
 }
 
 void FillShaderProto(ShaderProto* proto, const char* sha,
                      const Shader* shader) {
   proto->set_sha(sha, gpu::gles2::ProgramCache::kHashLength);
-  StoreShaderInfo(ATTRIB_MAP, proto, shader->attrib_map());
-  StoreShaderInfo(UNIFORM_MAP, proto, shader->uniform_map());
-  StoreShaderInfo(VARYING_MAP, proto, shader->varying_map());
+  for (AttributeMap::const_iterator iter = shader->attrib_map().begin();
+       iter != shader->attrib_map().end(); ++iter) {
+    ShaderAttributeProto* info = proto->add_attribs();
+    FillShaderAttributeProto(info, iter->second);
+  }
+  for (UniformMap::const_iterator iter = shader->uniform_map().begin();
+       iter != shader->uniform_map().end(); ++iter) {
+    ShaderUniformProto* info = proto->add_uniforms();
+    FillShaderUniformProto(info, iter->second);
+  }
+  for (VaryingMap::const_iterator iter = shader->varying_map().begin();
+       iter != shader->varying_map().end(); ++iter) {
+    ShaderVaryingProto* info = proto->add_varyings();
+    FillShaderVaryingProto(info, iter->second);
+  }
+}
+
+void RetrieveShaderVariableInfo(
+    const ShaderVariableProto& proto, sh::ShaderVariable* variable) {
+  variable->type = proto.type();
+  variable->precision = proto.precision();
+  variable->name = proto.name();
+  variable->mappedName = proto.mapped_name();
+  variable->arraySize = proto.array_size();
+  variable->staticUse = proto.static_use();
+  variable->fields.resize(proto.fields_size());
+  for (int ii = 0; ii < proto.fields_size(); ++ii)
+    RetrieveShaderVariableInfo(proto.fields(ii), &(variable->fields[ii]));
+  variable->structName = proto.struct_name();
+}
+
+void RetrieveShaderAttributeInfo(
+    const ShaderAttributeProto& proto, AttributeMap* map) {
+  sh::Attribute attrib;
+  RetrieveShaderVariableInfo(proto.basic(), &attrib);
+  attrib.location = proto.location();
+  (*map)[proto.basic().mapped_name()] = attrib;
+}
+
+void RetrieveShaderUniformInfo(
+    const ShaderUniformProto& proto, UniformMap* map) {
+  sh::Uniform uniform;
+  RetrieveShaderVariableInfo(proto.basic(), &uniform);
+  (*map)[proto.basic().mapped_name()] = uniform;
+}
+
+void RetrieveShaderVaryingInfo(
+    const ShaderVaryingProto& proto, VaryingMap* map) {
+  sh::Varying varying;
+  RetrieveShaderVariableInfo(proto.basic(), &varying);
+  varying.interpolation = static_cast<sh::InterpolationType>(
+      proto.interpolation());
+  varying.isInvariant = proto.is_invariant();
+  (*map)[proto.basic().mapped_name()] = varying;
 }
 
 void RunShaderCallback(const ShaderCacheCallback& callback,
@@ -270,39 +319,36 @@
 void MemoryProgramCache::LoadProgram(const std::string& program) {
   scoped_ptr<GpuProgramProto> proto(GpuProgramProto::default_instance().New());
   if (proto->ParseFromString(program)) {
-    ShaderTranslator::VariableMap vertex_attribs;
-    ShaderTranslator::VariableMap vertex_uniforms;
-    ShaderTranslator::VariableMap vertex_varyings;
-
+    AttributeMap vertex_attribs;
+    UniformMap vertex_uniforms;
+    VaryingMap vertex_varyings;
     for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) {
-      RetrieveShaderInfo(proto->vertex_shader().attribs(i), &vertex_attribs);
+      RetrieveShaderAttributeInfo(proto->vertex_shader().attribs(i),
+                                  &vertex_attribs);
     }
-
     for (int i = 0; i < proto->vertex_shader().uniforms_size(); i++) {
-      RetrieveShaderInfo(proto->vertex_shader().uniforms(i), &vertex_uniforms);
+      RetrieveShaderUniformInfo(proto->vertex_shader().uniforms(i),
+                                &vertex_uniforms);
     }
-
     for (int i = 0; i < proto->vertex_shader().varyings_size(); i++) {
-      RetrieveShaderInfo(proto->vertex_shader().varyings(i), &vertex_varyings);
+      RetrieveShaderVaryingInfo(proto->vertex_shader().varyings(i),
+                                &vertex_varyings);
     }
 
-    ShaderTranslator::VariableMap fragment_attribs;
-    ShaderTranslator::VariableMap fragment_uniforms;
-    ShaderTranslator::VariableMap fragment_varyings;
-
+    AttributeMap fragment_attribs;
+    UniformMap fragment_uniforms;
+    VaryingMap fragment_varyings;
     for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) {
-      RetrieveShaderInfo(proto->fragment_shader().attribs(i),
-                         &fragment_attribs);
+      RetrieveShaderAttributeInfo(proto->fragment_shader().attribs(i),
+                                  &fragment_attribs);
     }
-
     for (int i = 0; i < proto->fragment_shader().uniforms_size(); i++) {
-      RetrieveShaderInfo(proto->fragment_shader().uniforms(i),
-                         &fragment_uniforms);
+      RetrieveShaderUniformInfo(proto->fragment_shader().uniforms(i),
+                                &fragment_uniforms);
     }
-
     for (int i = 0; i < proto->fragment_shader().varyings_size(); i++) {
-      RetrieveShaderInfo(proto->fragment_shader().varyings(i),
-                         &fragment_varyings);
+      RetrieveShaderVaryingInfo(proto->fragment_shader().varyings(i),
+                                &fragment_varyings);
     }
 
     scoped_ptr<char[]> binary(new char[proto->program().length()]);
@@ -336,13 +382,13 @@
     const char* data,
     const std::string& program_hash,
     const char* shader_0_hash,
-    const ShaderTranslator::VariableMap& attrib_map_0,
-    const ShaderTranslator::VariableMap& uniform_map_0,
-    const ShaderTranslator::VariableMap& varying_map_0,
+    const AttributeMap& attrib_map_0,
+    const UniformMap& uniform_map_0,
+    const VaryingMap& varying_map_0,
     const char* shader_1_hash,
-    const ShaderTranslator::VariableMap& attrib_map_1,
-    const ShaderTranslator::VariableMap& uniform_map_1,
-    const ShaderTranslator::VariableMap& varying_map_1,
+    const AttributeMap& attrib_map_1,
+    const UniformMap& uniform_map_1,
+    const VaryingMap& varying_map_1,
     MemoryProgramCache* program_cache)
     : length_(length),
       format_(format),
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h
index 56e5979..804547e 100644
--- a/gpu/command_buffer/service/memory_program_cache.h
+++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -55,13 +55,13 @@
                       const char* data,
                       const std::string& program_hash,
                       const char* shader_0_hash,
-                      const ShaderTranslator::VariableMap& attrib_map_0,
-                      const ShaderTranslator::VariableMap& uniform_map_0,
-                      const ShaderTranslator::VariableMap& varying_map_0,
+                      const AttributeMap& attrib_map_0,
+                      const UniformMap& uniform_map_0,
+                      const VaryingMap& varying_map_0,
                       const char* shader_1_hash,
-                      const ShaderTranslator::VariableMap& attrib_map_1,
-                      const ShaderTranslator::VariableMap& uniform_map_1,
-                      const ShaderTranslator::VariableMap& varying_map_1,
+                      const AttributeMap& attrib_map_1,
+                      const UniformMap& uniform_map_1,
+                      const VaryingMap& varying_map_1,
                       MemoryProgramCache* program_cache);
 
     GLsizei length() const {
@@ -80,15 +80,15 @@
       return shader_0_hash_;
     }
 
-    const ShaderTranslator::VariableMap& attrib_map_0() const {
+    const AttributeMap& attrib_map_0() const {
       return attrib_map_0_;
     }
 
-    const ShaderTranslator::VariableMap& uniform_map_0() const {
+    const UniformMap& uniform_map_0() const {
       return uniform_map_0_;
     }
 
-    const ShaderTranslator::VariableMap& varying_map_0() const {
+    const VaryingMap& varying_map_0() const {
       return varying_map_0_;
     }
 
@@ -96,15 +96,15 @@
       return shader_1_hash_;
     }
 
-    const ShaderTranslator::VariableMap& attrib_map_1() const {
+    const AttributeMap& attrib_map_1() const {
       return attrib_map_1_;
     }
 
-    const ShaderTranslator::VariableMap& uniform_map_1() const {
+    const UniformMap& uniform_map_1() const {
       return uniform_map_1_;
     }
 
-    const ShaderTranslator::VariableMap& varying_map_1() const {
+    const VaryingMap& varying_map_1() const {
       return varying_map_1_;
     }
 
@@ -118,13 +118,13 @@
     const scoped_ptr<const char[]> data_;
     const std::string program_hash_;
     const std::string shader_0_hash_;
-    const ShaderTranslator::VariableMap attrib_map_0_;
-    const ShaderTranslator::VariableMap uniform_map_0_;
-    const ShaderTranslator::VariableMap varying_map_0_;
+    const AttributeMap attrib_map_0_;
+    const UniformMap uniform_map_0_;
+    const VaryingMap varying_map_0_;
     const std::string shader_1_hash_;
-    const ShaderTranslator::VariableMap attrib_map_1_;
-    const ShaderTranslator::VariableMap uniform_map_1_;
-    const ShaderTranslator::VariableMap varying_map_1_;
+    const AttributeMap attrib_map_1_;
+    const UniformMap uniform_map_1_;
+    const VaryingMap varying_map_1_;
     MemoryProgramCache* const program_cache_;
 
     DISALLOW_COPY_AND_ASSIGN(ProgramCacheValue);
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index ba18ff4..4ff3fe3 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -21,10 +21,6 @@
 using ::testing::SetArgPointee;
 using ::testing::SetArrayArgument;
 
-namespace {
-typedef gpu::gles2::ShaderTranslator::VariableMap VariableMap;
-}  // anonymous namespace
-
 namespace gpu {
 namespace gles2 {
 
@@ -105,24 +101,27 @@
         GL_FRAGMENT_SHADER);
     ASSERT_TRUE(vertex_shader_ != NULL);
     ASSERT_TRUE(fragment_shader_ != NULL);
-    typedef ShaderTranslatorInterface::VariableInfo VariableInfo;
-    typedef ShaderTranslator::VariableMap VariableMap;
-    VariableMap vertex_attrib_map;
-    VariableMap vertex_uniform_map;
-    VariableMap vertex_varying_map;
-    VariableMap fragment_attrib_map;
-    VariableMap fragment_uniform_map;
-    VariableMap fragment_varying_map;
+    AttributeMap vertex_attrib_map;
+    UniformMap vertex_uniform_map;
+    VaryingMap vertex_varying_map;
+    AttributeMap fragment_attrib_map;
+    UniformMap fragment_uniform_map;
+    VaryingMap fragment_varying_map;
 
-    vertex_attrib_map["a"] = VariableInfo(1, 34, SH_PRECISION_LOWP, 0, "a");
-    vertex_uniform_map["a"] = VariableInfo(0, 10, SH_PRECISION_MEDIUMP, 1, "a");
-    vertex_uniform_map["b"] = VariableInfo(2, 3114, SH_PRECISION_HIGHP, 1, "b");
-    vertex_varying_map["c"] = VariableInfo(3, 2, SH_PRECISION_HIGHP, 1, "c");
-    fragment_attrib_map["jjjbb"] =
-        VariableInfo(463, 1114, SH_PRECISION_MEDIUMP, 0, "jjjbb");
-    fragment_uniform_map["k"] =
-        VariableInfo(10, 34413, SH_PRECISION_MEDIUMP, 1, "k");
-    fragment_varying_map["c"] = VariableInfo(3, 2, SH_PRECISION_HIGHP, 1, "c");
+    vertex_attrib_map["a"] = TestHelper::ConstructAttribute(
+        GL_FLOAT_VEC2, 34, GL_LOW_FLOAT, false, "a");
+    vertex_uniform_map["a"] = TestHelper::ConstructUniform(
+        GL_FLOAT, 10, GL_MEDIUM_FLOAT, true, "a");
+    vertex_uniform_map["b"] = TestHelper::ConstructUniform(
+        GL_FLOAT_VEC3, 3114, GL_HIGH_FLOAT, true, "b");
+    vertex_varying_map["c"] = TestHelper::ConstructVarying(
+        GL_FLOAT_VEC4, 2, GL_HIGH_FLOAT, true, "c");
+    fragment_attrib_map["jjjbb"] = TestHelper::ConstructAttribute(
+        GL_FLOAT_MAT4, 1114, GL_MEDIUM_FLOAT, false, "jjjbb");
+    fragment_uniform_map["k"] = TestHelper::ConstructUniform(
+        GL_FLOAT_MAT2, 34413, GL_MEDIUM_FLOAT, true, "k");
+    fragment_varying_map["c"] = TestHelper::ConstructVarying(
+        GL_FLOAT_VEC4, 2, GL_HIGH_FLOAT, true, "c");
 
     vertex_shader_->set_source("bbbalsldkdkdkd");
     fragment_shader_->set_source("bbbal   sldkdkdkas 134 ad");
@@ -261,19 +260,19 @@
                                        base::Unretained(this)));
   EXPECT_EQ(1, shader_cache_count());
 
-  VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
-  VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
-  VariableMap vertex_varying_map = vertex_shader_->varying_map();
-  VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
-  VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
-  VariableMap fragment_varying_map = fragment_shader_->varying_map();
+  AttributeMap vertex_attrib_map = vertex_shader_->attrib_map();
+  UniformMap vertex_uniform_map = vertex_shader_->uniform_map();
+  VaryingMap vertex_varying_map = vertex_shader_->varying_map();
+  AttributeMap fragment_attrib_map = fragment_shader_->attrib_map();
+  UniformMap fragment_uniform_map = fragment_shader_->uniform_map();
+  VaryingMap fragment_varying_map = fragment_shader_->varying_map();
 
-  vertex_shader_->set_attrib_map(VariableMap());
-  vertex_shader_->set_uniform_map(VariableMap());
-  vertex_shader_->set_varying_map(VariableMap());
-  fragment_shader_->set_attrib_map(VariableMap());
-  fragment_shader_->set_uniform_map(VariableMap());
-  fragment_shader_->set_varying_map(VariableMap());
+  vertex_shader_->set_attrib_map(AttributeMap());
+  vertex_shader_->set_uniform_map(UniformMap());
+  vertex_shader_->set_varying_map(VaryingMap());
+  fragment_shader_->set_attrib_map(AttributeMap());
+  fragment_shader_->set_uniform_map(UniformMap());
+  fragment_shader_->set_varying_map(VaryingMap());
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
@@ -316,19 +315,19 @@
                                        base::Unretained(this)));
   EXPECT_EQ(1, shader_cache_count());
 
-  VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
-  VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
-  VariableMap vertex_varying_map = vertex_shader_->varying_map();
-  VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
-  VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
-  VariableMap fragment_varying_map = fragment_shader_->varying_map();
+  AttributeMap vertex_attrib_map = vertex_shader_->attrib_map();
+  UniformMap vertex_uniform_map = vertex_shader_->uniform_map();
+  VaryingMap vertex_varying_map = vertex_shader_->varying_map();
+  AttributeMap fragment_attrib_map = fragment_shader_->attrib_map();
+  UniformMap fragment_uniform_map = fragment_shader_->uniform_map();
+  VaryingMap fragment_varying_map = fragment_shader_->varying_map();
 
-  vertex_shader_->set_attrib_map(VariableMap());
-  vertex_shader_->set_uniform_map(VariableMap());
-  vertex_shader_->set_varying_map(VariableMap());
-  fragment_shader_->set_attrib_map(VariableMap());
-  fragment_shader_->set_uniform_map(VariableMap());
-  fragment_shader_->set_varying_map(VariableMap());
+  vertex_shader_->set_attrib_map(AttributeMap());
+  vertex_shader_->set_uniform_map(UniformMap());
+  vertex_shader_->set_varying_map(VaryingMap());
+  fragment_shader_->set_attrib_map(AttributeMap());
+  fragment_shader_->set_uniform_map(UniformMap());
+  fragment_shader_->set_varying_map(VaryingMap());
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h
index 17c8401..87b3136 100644
--- a/gpu/command_buffer/service/mocks.h
+++ b/gpu/command_buffer/service/mocks.h
@@ -100,9 +100,9 @@
       const std::string& shader_source,
       std::string* info_log,
       std::string* translated_source,
-      VariableMap* attrib_map,
-      VariableMap* uniform_map,
-      VariableMap* varying_map,
+      AttributeMap* attrib_map,
+      UniformMap* uniform_map,
+      VaryingMap* varying_map,
       NameMap* name_map));
   MOCK_CONST_METHOD0(
       GetStringForOptionsThatWouldAffectCompilation, std::string());
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 4dd4bc4..e8196f6 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -15,6 +15,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
@@ -33,28 +34,6 @@
 
 namespace {
 
-struct UniformType {
-  explicit UniformType(const ShaderTranslator::VariableInfo uniform)
-      : type(uniform.type),
-        size(uniform.size),
-        precision(uniform.precision) { }
-
-  UniformType()
-      : type(0),
-        size(0),
-        precision(SH_PRECISION_MEDIUMP) { }
-
-  bool operator==(const UniformType& other) const {
-    return type == other.type &&
-        size == other.size &&
-        precision == other.precision;
-  }
-
-  int type;
-  int size;
-  int precision;
-};
-
 int ShaderTypeToIndex(GLenum shader_type) {
   switch (shader_type) {
     case GL_VERTEX_SHADER:
@@ -389,17 +368,15 @@
     DCHECK(max_len == 0 || length < max_len);
     DCHECK(length == 0 || name_buffer[length] == '\0');
     if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
-      std::string name;
       std::string original_name;
-      GetCorrectedVariableInfo(
-          false, name_buffer.get(), &name, &original_name, &size, &type);
+      GetVertexAttribData(name_buffer.get(), &original_name, &type);
       // TODO(gman): Should we check for error?
       GLint location = glGetAttribLocation(service_id_, name_buffer.get());
       if (location > max_location) {
         max_location = location;
       }
       attrib_infos_.push_back(
-          VertexAttrib(size, type, original_name, location));
+          VertexAttrib(1, type, original_name, location));
       max_attrib_name_length_ = std::max(
           max_attrib_name_length_, static_cast<GLsizei>(original_name.size()));
     }
@@ -447,9 +424,9 @@
     DCHECK(length == 0 || name_buffer[length] == '\0');
     if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
       data.queried_name = std::string(name_buffer.get());
-      GetCorrectedVariableInfo(
-          true, name_buffer.get(), &data.corrected_name, &data.original_name,
-          &data.size, &data.type);
+      GetCorrectedUniformData(
+          data.queried_name,
+          &data.corrected_name, &data.original_name, &data.size, &data.type);
       uniform_data.push_back(data);
     }
   }
@@ -471,8 +448,8 @@
     // remove "[0]"
     std::string short_name;
     int element_index = 0;
-    bool good ALLOW_UNUSED = GetUniformNameSansElement(
-        data.queried_name, &element_index, &short_name);\
+    bool good = GetUniformNameSansElement(data.queried_name, &element_index,
+                                          &short_name);
     DCHECK(good);
     LocationMap::const_iterator it = bind_uniform_location_map_.find(
         short_name);
@@ -516,7 +493,7 @@
   for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
        it != bind_attrib_location_map_.end(); ++it) {
     const std::string* mapped_name = GetAttribMappedName(it->first);
-    if (mapped_name && *mapped_name != it->first)
+    if (mapped_name)
       glBindAttribLocation(service_id_, it->second, mapped_name->c_str());
   }
 }
@@ -678,10 +655,10 @@
 }
 
 GLint Program::GetAttribLocation(
-    const std::string& name) const {
+    const std::string& original_name) const {
   for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
     const VertexAttrib& info = attrib_infos_[ii];
-    if (info.name == name) {
+    if (info.name == original_name) {
       return info.location;
     }
   }
@@ -757,41 +734,60 @@
 
 // Note: This is only valid to call right after a program has been linked
 // successfully.
-void Program::GetCorrectedVariableInfo(
-    bool use_uniforms,
-    const std::string& name, std::string* corrected_name,
-    std::string* original_name,
+void Program::GetCorrectedUniformData(
+    const std::string& name,
+    std::string* corrected_name, std::string* original_name,
     GLsizei* size, GLenum* type) const {
-  DCHECK(corrected_name);
-  DCHECK(original_name);
-  DCHECK(size);
-  DCHECK(type);
-  const char* kArraySpec = "[0]";
-  for (int jj = 0; jj < 2; ++jj) {
-    std::string test_name(name + ((jj == 1) ? kArraySpec : ""));
-    for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
-      Shader* shader = attached_shaders_[ii].get();
-      if (shader) {
-        const Shader::VariableInfo* variable_info =
-            use_uniforms ? shader->GetUniformInfo(test_name) :
-                           shader->GetAttribInfo(test_name);
-        // Note: There is an assuption here that if an attrib is defined in more
-        // than 1 attached shader their types and sizes match. Should we check
-        // for that case?
-        if (variable_info) {
-          *corrected_name = test_name;
-          *original_name = variable_info->name;
-          *type = variable_info->type;
-          *size = variable_info->size;
-          return;
-        }
+  DCHECK(corrected_name && original_name && size && type);
+  for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+    Shader* shader = attached_shaders_[ii].get();
+    if (!shader)
+      continue;
+    const sh::ShaderVariable* info = NULL;
+    const sh::Uniform* uniform = shader->GetUniformInfo(name);
+    bool found = false;
+    if (uniform)
+      found = uniform->findInfoByMappedName(name, &info, original_name);
+    if (found) {
+      const std::string kArraySpec("[0]");
+      if (info->arraySize > 0 && !EndsWith(name, kArraySpec, true)) {
+        *corrected_name = name + kArraySpec;
+        *original_name += kArraySpec;
+      } else {
+        *corrected_name = name;
       }
+      *type = info->type;
+      *size = std::max(1u, info->arraySize);
+      return;
     }
   }
+  // TODO(zmo): this path should never be reached unless there is a serious
+  // bug in the driver or in ANGLE translator.
   *corrected_name = name;
   *original_name = name;
 }
 
+void Program::GetVertexAttribData(
+    const std::string& name, std::string* original_name, GLenum* type) const {
+  DCHECK(original_name);
+  DCHECK(type);
+  Shader* shader = attached_shaders_[ShaderTypeToIndex(GL_VERTEX_SHADER)].get();
+  if (shader) {
+    // Vertex attributes can not be arrays or structs (GLSL ES 3.00.4, section
+    // 4.3.4, "Input Variables"), so the top level sh::Attribute returns the
+    // information we need.
+    const sh::Attribute* info = shader->GetAttribInfo(name);
+    if (info) {
+      *original_name = info->name;
+      *type = info->type;
+      return;
+    }
+  }
+  // TODO(zmo): this path should never be reached unless there is a serious
+  // bug in the driver or in ANGLE translator.
+  *original_name = name;
+}
+
 bool Program::AddUniformInfo(
         GLsizei size, GLenum type, GLint location, GLint fake_base_location,
         const std::string& name, const std::string& original_name,
@@ -993,44 +989,64 @@
   std::set<GLint> location_binding_used;
   for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
        it != bind_attrib_location_map_.end(); ++it) {
-    // Find out if an attribute is declared in this program's shaders.
-    bool active = false;
+    // Find out if an attribute is statically used in this program's shaders.
+    const sh::Attribute* attrib = NULL;
+    const std::string* mapped_name = GetAttribMappedName(it->first);
+    if (!mapped_name)
+      continue;
     for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
       if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid())
         continue;
-      if (attached_shaders_[ii]->GetAttribInfo(it->first)) {
-        active = true;
-        break;
+      attrib = attached_shaders_[ii]->GetAttribInfo(*mapped_name);
+      if (attrib) {
+        if (attrib->staticUse)
+          break;
+        else
+          attrib = NULL;
       }
     }
-    if (active) {
-      std::pair<std::set<GLint>::iterator, bool> result =
-          location_binding_used.insert(it->second);
-      if (!result.second)
-        return true;
+    if (attrib) {
+      size_t num_of_locations = 1;
+      switch (attrib->type) {
+        case GL_FLOAT_MAT2:
+          num_of_locations = 2;
+          break;
+        case GL_FLOAT_MAT3:
+          num_of_locations = 3;
+          break;
+        case GL_FLOAT_MAT4:
+          num_of_locations = 4;
+          break;
+        default:
+          break;
+      }
+      for (size_t ii = 0; ii < num_of_locations; ++ii) {
+        GLint loc = it->second + ii;
+        std::pair<std::set<GLint>::iterator, bool> result =
+            location_binding_used.insert(loc);
+        if (!result.second)
+          return true;
+      }
     }
   }
   return false;
 }
 
 bool Program::DetectUniformsMismatch(std::string* conflicting_name) const {
-  typedef std::map<std::string, UniformType> UniformMap;
-  UniformMap uniform_map;
+  typedef std::map<std::string, const sh::Uniform*> UniformPointerMap;
+  UniformPointerMap uniform_pointer_map;
   for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
-    const ShaderTranslator::VariableMap& shader_uniforms =
-        attached_shaders_[ii]->uniform_map();
-    for (ShaderTranslator::VariableMap::const_iterator iter =
-             shader_uniforms.begin();
+    const UniformMap& shader_uniforms = attached_shaders_[ii]->uniform_map();
+    for (UniformMap::const_iterator iter = shader_uniforms.begin();
          iter != shader_uniforms.end(); ++iter) {
       const std::string& name = iter->first;
-      UniformType type(iter->second);
-      UniformMap::iterator map_entry = uniform_map.find(name);
-      if (map_entry == uniform_map.end()) {
-        uniform_map[name] = type;
+      UniformPointerMap::iterator hit = uniform_pointer_map.find(name);
+      if (hit == uniform_pointer_map.end()) {
+        uniform_pointer_map[name] = &(iter->second);
       } else {
-        // If a uniform is already in the map, i.e., it has already been
-        // declared by other shader, then the type and precision must match.
-        if (map_entry->second == type)
+        // If a uniform is in the map, i.e., it has already been declared by
+        // another shader, then the type, precision, etc. must match.
+        if (hit->second->isSameUniformAtLinkTime(iter->second))
           continue;
         *conflicting_name = name;
         return true;
@@ -1045,30 +1061,25 @@
          attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
          attached_shaders_[1].get() &&
          attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
-  const ShaderTranslator::VariableMap* vertex_varyings =
-      &(attached_shaders_[0]->varying_map());
-  const ShaderTranslator::VariableMap* fragment_varyings =
-      &(attached_shaders_[1]->varying_map());
+  const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
+  const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
 
-  for (ShaderTranslator::VariableMap::const_iterator iter =
-           fragment_varyings->begin();
+  for (VaryingMap::const_iterator iter = fragment_varyings->begin();
        iter != fragment_varyings->end(); ++iter) {
     const std::string& name = iter->first;
     if (IsBuiltInVarying(name))
       continue;
 
-    ShaderTranslator::VariableMap::const_iterator hit =
-        vertex_varyings->find(name);
+    VaryingMap::const_iterator hit = vertex_varyings->find(name);
     if (hit == vertex_varyings->end()) {
-      if (iter->second.static_use) {
+      if (iter->second.staticUse) {
         *conflicting_name = name;
         return true;
       }
       continue;
     }
 
-    if (hit->second.type != iter->second.type ||
-        hit->second.size != iter->second.size) {
+    if (!hit->second.isSameVaryingAtLinkTime(iter->second)) {
       *conflicting_name = name;
       return true;
     }
@@ -1082,14 +1093,14 @@
          attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
          attached_shaders_[1].get() &&
          attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
-  const ShaderTranslator::VariableMap* uniforms[2];
+  const UniformMap* uniforms[2];
   uniforms[0] = &(attached_shaders_[0]->uniform_map());
   uniforms[1] = &(attached_shaders_[1]->uniform_map());
-  const ShaderTranslator::VariableMap* attribs =
+  const AttributeMap* attribs =
       &(attached_shaders_[0]->attrib_map());
 
-  for (ShaderTranslator::VariableMap::const_iterator iter =
-           attribs->begin(); iter != attribs->end(); ++iter) {
+  for (AttributeMap::const_iterator iter = attribs->begin();
+       iter != attribs->end(); ++iter) {
     for (int ii = 0; ii < 2; ++ii) {
       if (uniforms[ii]->find(iter->first) != uniforms[ii]->end()) {
         *conflicting_name = iter->first;
@@ -1106,30 +1117,27 @@
          attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
          attached_shaders_[1].get() &&
          attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
-  const ShaderTranslator::VariableMap* vertex_varyings =
-      &(attached_shaders_[0]->varying_map());
-  const ShaderTranslator::VariableMap* fragment_varyings =
-      &(attached_shaders_[1]->varying_map());
+  const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
+  const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
 
   std::map<std::string, ShVariableInfo> combined_map;
 
-  for (ShaderTranslator::VariableMap::const_iterator iter =
-           fragment_varyings->begin();
+  for (VaryingMap::const_iterator iter = fragment_varyings->begin();
        iter != fragment_varyings->end(); ++iter) {
-    if (!iter->second.static_use && option == kCountOnlyStaticallyUsed)
+    if (!iter->second.staticUse && option == kCountOnlyStaticallyUsed)
       continue;
     if (!IsBuiltInVarying(iter->first)) {
-      ShaderTranslator::VariableMap::const_iterator vertex_iter =
+      VaryingMap::const_iterator vertex_iter =
           vertex_varyings->find(iter->first);
       if (vertex_iter == vertex_varyings->end() ||
-          (!vertex_iter->second.static_use &&
+          (!vertex_iter->second.staticUse &&
            option == kCountOnlyStaticallyUsed))
         continue;
     }
 
     ShVariableInfo var;
     var.type = static_cast<sh::GLenum>(iter->second.type);
-    var.size = iter->second.size;
+    var.size = std::max(1u, iter->second.arraySize);
     combined_map[iter->first] = var;
   }
 
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index bcc3630..9698fc1 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -79,7 +79,7 @@
   };
   struct VertexAttrib {
     VertexAttrib(GLsizei _size, GLenum _type, const std::string& _name,
-                     GLint _location)
+                 GLint _location)
         : size(_size),
           type(_type),
           location(_location),
@@ -115,7 +115,7 @@
        &attrib_infos_[index] : NULL;
   }
 
-  GLint GetAttribLocation(const std::string& name) const;
+  GLint GetAttribLocation(const std::string& original_name) const;
 
   const VertexAttrib* GetAttribInfoByLocation(GLuint location) const {
     if (location < attrib_location_to_index_map_.size()) {
@@ -281,9 +281,17 @@
       const std::string& name, const std::string& original_name,
       size_t* next_available_index);
 
-  void GetCorrectedVariableInfo(
-      bool use_uniforms, const std::string& name, std::string* corrected_name,
-      std::string* original_name, GLsizei* size, GLenum* type) const;
+  // Query uniform data returned by ANGLE translator by the mapped name.
+  // Some drivers incorrectly return an uniform name of size-1 array without
+  // "[0]". In this case, we correct the name by appending "[0]" to it.
+  void GetCorrectedUniformData(
+      const std::string& name,
+      std::string* corrected_name, std::string* original_name,
+      GLsizei* size, GLenum* type) const;
+
+  // Query VertexAttrib data returned by ANGLE translator by the mapped name.
+  void GetVertexAttribData(
+      const std::string& name, std::string* original_name, GLenum* type) const;
 
   void DetachShaders(ShaderManager* manager);
 
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 3cca263..5d80694 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -151,10 +151,10 @@
   static const GLint kAttrib1Size = 1;
   static const GLint kAttrib2Size = 1;
   static const GLint kAttrib3Size = 1;
-  static const int kAttrib1Precision = SH_PRECISION_MEDIUMP;
-  static const int kAttrib2Precision = SH_PRECISION_HIGHP;
-  static const int kAttrib3Precision = SH_PRECISION_LOWP;
-  static const int kAttribStaticUse = 0;
+  static const GLenum kAttrib1Precision = GL_MEDIUM_FLOAT;
+  static const GLenum kAttrib2Precision = GL_HIGH_FLOAT;
+  static const GLenum kAttrib3Precision = GL_LOW_FLOAT;
+  static const bool kAttribStaticUse = true;
   static const GLint kAttrib1Location = 0;
   static const GLint kAttrib2Location = 1;
   static const GLint kAttrib3Location = 2;
@@ -166,8 +166,9 @@
 
   static const char* kUniform1Name;
   static const char* kUniform2Name;
-  static const char* kUniform3BadName;
-  static const char* kUniform3GoodName;
+  static const char* kUniform2NameWithArrayIndex;
+  static const char* kUniform3Name;
+  static const char* kUniform3NameWithArrayIndex;
   static const GLint kUniform1Size = 1;
   static const GLint kUniform2Size = 3;
   static const GLint kUniform3Size = 2;
@@ -206,10 +207,10 @@
   } VarCategory;
 
   typedef struct {
-    int type;
-    int size;
-    int precision;
-    int static_use;
+    GLenum type;
+    GLint size;
+    GLenum precision;
+    bool static_use;
     std::string name;
     VarCategory category;
   } VarInfo;
@@ -283,56 +284,78 @@
     const GLuint kFShaderClientId = 2;
     const GLuint kFShaderServiceId = 12;
 
-    ShaderTranslator::VariableMap vertex_attrib_map;
-    ShaderTranslator::VariableMap vertex_uniform_map;
-    ShaderTranslator::VariableMap vertex_varying_map;
+    AttributeMap vertex_attrib_map;
+    UniformMap vertex_uniform_map;
+    VaryingMap vertex_varying_map;
     for (size_t ii = 0; ii < vertex_variable_size; ++ii) {
-      ShaderTranslator::VariableMap* map = NULL;
       switch (vertex_variables[ii].category) {
         case kVarAttribute:
-          map = &vertex_attrib_map;
+          vertex_attrib_map[vertex_variables[ii].name] =
+              TestHelper::ConstructAttribute(
+                  vertex_variables[ii].type,
+                  vertex_variables[ii].size,
+                  vertex_variables[ii].precision,
+                  vertex_variables[ii].static_use,
+                  vertex_variables[ii].name);
           break;
         case kVarUniform:
-          map = &vertex_uniform_map;
+          vertex_uniform_map[vertex_variables[ii].name] =
+              TestHelper::ConstructUniform(
+                  vertex_variables[ii].type,
+                  vertex_variables[ii].size,
+                  vertex_variables[ii].precision,
+                  vertex_variables[ii].static_use,
+                  vertex_variables[ii].name);
           break;
         case kVarVarying:
-          map = &vertex_varying_map;
+          vertex_varying_map[vertex_variables[ii].name] =
+              TestHelper::ConstructVarying(
+                  vertex_variables[ii].type,
+                  vertex_variables[ii].size,
+                  vertex_variables[ii].precision,
+                  vertex_variables[ii].static_use,
+                  vertex_variables[ii].name);
           break;
         default:
           NOTREACHED();
       }
-      (*map)[vertex_variables[ii].name] =
-          ShaderTranslator::VariableInfo(vertex_variables[ii].type,
-                                         vertex_variables[ii].size,
-                                         vertex_variables[ii].precision,
-                                         vertex_variables[ii].static_use,
-                                         vertex_variables[ii].name);
     }
 
-    ShaderTranslator::VariableMap frag_attrib_map;
-    ShaderTranslator::VariableMap frag_uniform_map;
-    ShaderTranslator::VariableMap frag_varying_map;
+    AttributeMap frag_attrib_map;
+    UniformMap frag_uniform_map;
+    VaryingMap frag_varying_map;
     for (size_t ii = 0; ii < fragment_variable_size; ++ii) {
-      ShaderTranslator::VariableMap* map = NULL;
       switch (fragment_variables[ii].category) {
         case kVarAttribute:
-          map = &frag_attrib_map;
+          frag_attrib_map[fragment_variables[ii].name] =
+              TestHelper::ConstructAttribute(
+                  fragment_variables[ii].type,
+                  fragment_variables[ii].size,
+                  fragment_variables[ii].precision,
+                  fragment_variables[ii].static_use,
+                  fragment_variables[ii].name);
           break;
         case kVarUniform:
-          map = &frag_uniform_map;
+          frag_uniform_map[fragment_variables[ii].name] =
+              TestHelper::ConstructUniform(
+                  fragment_variables[ii].type,
+                  fragment_variables[ii].size,
+                  fragment_variables[ii].precision,
+                  fragment_variables[ii].static_use,
+                  fragment_variables[ii].name);
           break;
         case kVarVarying:
-          map = &frag_varying_map;
+          frag_varying_map[fragment_variables[ii].name] =
+              TestHelper::ConstructVarying(
+                  fragment_variables[ii].type,
+                  fragment_variables[ii].size,
+                  fragment_variables[ii].precision,
+                  fragment_variables[ii].static_use,
+                  fragment_variables[ii].name);
           break;
         default:
           NOTREACHED();
       }
-      (*map)[fragment_variables[ii].name] =
-          ShaderTranslator::VariableInfo(fragment_variables[ii].type,
-                                         fragment_variables[ii].size,
-                                         fragment_variables[ii].precision,
-                                         fragment_variables[ii].static_use,
-                                         fragment_variables[ii].name);
     }
 
     // Check we can create shader.
@@ -434,15 +457,15 @@
     kUniform2FakeLocation,
     kUniform2RealLocation,
     kUniform2DesiredLocation,
-    kUniform2Name,
+    kUniform2NameWithArrayIndex,
   },
-  { kUniform3BadName,
+  { kUniform3Name,
     kUniform3Size,
     kUniform3Type,
     kUniform3FakeLocation,
     kUniform3RealLocation,
     kUniform3DesiredLocation,
-    kUniform3GoodName,
+    kUniform3NameWithArrayIndex,
   },
 };
 
@@ -453,11 +476,12 @@
 const char* ProgramManagerWithShaderTest::kAttrib2Name = "attrib2";
 const char* ProgramManagerWithShaderTest::kAttrib3Name = "attrib3";
 const char* ProgramManagerWithShaderTest::kUniform1Name = "uniform1";
-// Correctly has array spec.
-const char* ProgramManagerWithShaderTest::kUniform2Name = "uniform2[0]";
-// Incorrectly missing array spec.
-const char* ProgramManagerWithShaderTest::kUniform3BadName = "uniform3";
-const char* ProgramManagerWithShaderTest::kUniform3GoodName = "uniform3[0]";
+const char* ProgramManagerWithShaderTest::kUniform2Name = "uniform2";
+const char* ProgramManagerWithShaderTest::kUniform2NameWithArrayIndex =
+    "uniform2[0]";
+const char* ProgramManagerWithShaderTest::kUniform3Name = "uniform3";
+const char* ProgramManagerWithShaderTest::kUniform3NameWithArrayIndex =
+    "uniform3[0]";
 
 TEST_F(ProgramManagerWithShaderTest, GetAttribInfos) {
   const Program* program = manager_.GetProgram(kClientProgramId);
@@ -514,7 +538,7 @@
   EXPECT_EQ(kUniform2Size, info->size);
   EXPECT_EQ(kUniform2Type, info->type);
   EXPECT_EQ(kUniform2RealLocation, info->element_locations[0]);
-  EXPECT_STREQ(kUniform2Name, info->name.c_str());
+  EXPECT_STREQ(kUniform2NameWithArrayIndex, info->name.c_str());
   info = program->GetUniformInfo(2);
   // We emulate certain OpenGL drivers by supplying the name without
   // the array spec. Our implementation should correctly add the required spec.
@@ -522,7 +546,7 @@
   EXPECT_EQ(kUniform3Size, info->size);
   EXPECT_EQ(kUniform3Type, info->type);
   EXPECT_EQ(kUniform3RealLocation, info->element_locations[0]);
-  EXPECT_STREQ(kUniform3GoodName, info->name.c_str());
+  EXPECT_STREQ(kUniform3NameWithArrayIndex, info->name.c_str());
   EXPECT_TRUE(program->GetUniformInfo(kInvalidIndex) == NULL);
 }
 
@@ -586,7 +610,7 @@
   EXPECT_EQ(kUniform2FakeLocation,
             program->GetUniformFakeLocation(kUniform2Name));
   EXPECT_EQ(kUniform3FakeLocation,
-            program->GetUniformFakeLocation(kUniform3BadName));
+            program->GetUniformFakeLocation(kUniform3Name));
   // Check we can get uniform2 as "uniform2" even though the name is
   // "uniform2[0]"
   EXPECT_EQ(kUniform2FakeLocation,
@@ -594,7 +618,7 @@
   // Check we can get uniform3 as "uniform3[0]" even though we simulated GL
   // returning "uniform3"
   EXPECT_EQ(kUniform3FakeLocation,
-            program->GetUniformFakeLocation(kUniform3GoodName));
+            program->GetUniformFakeLocation(kUniform3NameWithArrayIndex));
   // Check that we can get the locations of the array elements > 1
   EXPECT_EQ(ProgramManager::MakeFakeLocation(kUniform2FakeLocation, 1),
             program->GetUniformFakeLocation("uniform2[1]"));
@@ -653,15 +677,15 @@
       kUniform2FakeLocation,
       kUniform2RealLocation,
       kUniform2DesiredLocation,
-      kUniform2Name,
+      kUniform2NameWithArrayIndex,
     },
-    { kUniform3BadName,
+    { kUniform3Name,
       kUniform3Size,
       kUniform3Type,
       kUniform3FakeLocation,
       kUniform3RealLocation,
       kUniform3DesiredLocation,
-      kUniform3GoodName,
+      kUniform3NameWithArrayIndex,
     },
   };
   const size_t kNumUniforms = arraysize(kUniforms);
@@ -698,7 +722,7 @@
   // as the "gl_" uniform we skipped.
   // +4u is to account for "gl_" and NULL terminator.
   program->GetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH, &value);
-  EXPECT_EQ(strlen(kUniform3BadName) + 4u, static_cast<size_t>(value));
+  EXPECT_EQ(strlen(kUniform3Name) + 4u, static_cast<size_t>(value));
 }
 
 // Test the bug comparing similar array names is fixed.
@@ -772,27 +796,27 @@
   static GLenum kAttrib2GoodType = GL_FLOAT_MAT2;
   static GLenum kUniform2BadType = GL_FLOAT_VEC3;
   static GLenum kUniform2GoodType = GL_FLOAT_MAT3;
-  ShaderTranslator::VariableMap attrib_map;
-  ShaderTranslator::VariableMap uniform_map;
-  ShaderTranslator::VariableMap varying_map;
-  attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo(
+  AttributeMap attrib_map;
+  UniformMap uniform_map;
+  VaryingMap varying_map;
+  attrib_map[kAttrib1Name] = TestHelper::ConstructAttribute(
       kAttrib1Type, kAttrib1Size, kAttrib1Precision,
       kAttribStaticUse, kAttrib1Name);
-  attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo(
+  attrib_map[kAttrib2Name] = TestHelper::ConstructAttribute(
       kAttrib2GoodType, kAttrib2Size, kAttrib2Precision,
       kAttribStaticUse, kAttrib2Name);
-  attrib_map[kAttrib3Name] = ShaderTranslatorInterface::VariableInfo(
+  attrib_map[kAttrib3Name] = TestHelper::ConstructAttribute(
       kAttrib3Type, kAttrib3Size, kAttrib3Precision,
       kAttribStaticUse, kAttrib3Name);
-  uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo(
+  uniform_map[kUniform1Name] = TestHelper::ConstructUniform(
       kUniform1Type, kUniform1Size, kUniform1Precision,
       kUniform1StaticUse, kUniform1Name);
-  uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo(
+  uniform_map[kUniform2Name] = TestHelper::ConstructUniform(
       kUniform2GoodType, kUniform2Size, kUniform2Precision,
       kUniform2StaticUse, kUniform2Name);
-  uniform_map[kUniform3GoodName] = ShaderTranslatorInterface::VariableInfo(
+  uniform_map[kUniform3Name] = TestHelper::ConstructUniform(
       kUniform3Type, kUniform3Size, kUniform3Precision,
-      kUniform3StaticUse, kUniform3GoodName);
+      kUniform3StaticUse, kUniform3Name);
   const GLuint kVShaderClientId = 2001;
   const GLuint kFShaderClientId = 2002;
   const GLuint kVShaderServiceId = 3001;
@@ -829,15 +853,15 @@
       kUniform2FakeLocation,
       kUniform2RealLocation,
       kUniform2DesiredLocation,
-      kUniform2Name,
+      kUniform2NameWithArrayIndex,
     },
-    { kUniform3BadName,
+    { kUniform3Name,
       kUniform3Size,
       kUniform3Type,
       kUniform3FakeLocation,
       kUniform3RealLocation,
       kUniform3DesiredLocation,
-      kUniform3GoodName,
+      kUniform3NameWithArrayIndex,
     },
   };
   const size_t kNumAttribs= arraysize(kAttribs);
@@ -859,26 +883,41 @@
     const Program::VertexAttrib* attrib_info =
         program->GetAttribInfo(index);
     ASSERT_TRUE(attrib_info != NULL);
-    ShaderTranslator::VariableMap::const_iterator it = attrib_map.find(
-        attrib_info->name);
+    size_t pos = attrib_info->name.find_first_of("[.");
+    std::string top_name;
+    if (pos == std::string::npos)
+      top_name = attrib_info->name;
+    else
+      top_name = attrib_info->name.substr(0, pos);
+    AttributeMap::const_iterator it = attrib_map.find(top_name);
     ASSERT_TRUE(it != attrib_map.end());
-    EXPECT_EQ(it->first, attrib_info->name);
-    EXPECT_EQ(static_cast<GLenum>(it->second.type), attrib_info->type);
-    EXPECT_EQ(it->second.size, attrib_info->size);
-    EXPECT_EQ(it->second.name, attrib_info->name);
+    const sh::ShaderVariable* info;
+    std::string original_name;
+    EXPECT_TRUE(it->second.findInfoByMappedName(
+        attrib_info->name, &info, &original_name));
+    EXPECT_EQ(info->type, attrib_info->type);
+    EXPECT_EQ(static_cast<GLint>(info->arraySize), attrib_info->size);
+    EXPECT_EQ(original_name, attrib_info->name);
   }
   // Check Uniforms
   for (unsigned index = 0; index < kNumUniforms; ++index) {
-    const Program::UniformInfo* uniform_info =
-        program->GetUniformInfo(index);
+    const Program::UniformInfo* uniform_info = program->GetUniformInfo(index);
     ASSERT_TRUE(uniform_info != NULL);
-    ShaderTranslator::VariableMap::const_iterator it = uniform_map.find(
-        uniform_info->name);
+    size_t pos = uniform_info->name.find_first_of("[.");
+    std::string top_name;
+    if (pos == std::string::npos)
+      top_name = uniform_info->name;
+    else
+      top_name = uniform_info->name.substr(0, pos);
+    UniformMap::const_iterator it = uniform_map.find(top_name);
     ASSERT_TRUE(it != uniform_map.end());
-    EXPECT_EQ(it->first, uniform_info->name);
-    EXPECT_EQ(static_cast<GLenum>(it->second.type), uniform_info->type);
-    EXPECT_EQ(it->second.size, uniform_info->size);
-    EXPECT_EQ(it->second.name, uniform_info->name);
+    const sh::ShaderVariable* info;
+    std::string original_name;
+    EXPECT_TRUE(it->second.findInfoByMappedName(
+        uniform_info->name, &info, &original_name));
+    EXPECT_EQ(info->type, uniform_info->type);
+    EXPECT_EQ(static_cast<GLint>(info->arraySize), uniform_info->size);
+    EXPECT_EQ(original_name, uniform_info->name);
   }
 }
 
@@ -1086,15 +1125,22 @@
   const GLuint kVShaderServiceId = 11;
   const GLuint kFShaderClientId = 2;
   const GLuint kFShaderServiceId = 12;
-  ShaderTranslator::VariableMap attrib_map;
+  AttributeMap attrib_map;
   for (uint32 ii = 0; ii < kNumAttribs; ++ii) {
-    attrib_map[kAttribs[ii].name] = ShaderTranslatorInterface::VariableInfo(
+    attrib_map[kAttribs[ii].name] = TestHelper::ConstructAttribute(
         kAttribs[ii].type,
         kAttribs[ii].size,
         SH_PRECISION_MEDIUMP,
         kAttribStaticUse,
         kAttribs[ii].name);
   }
+  const char kAttribMatName[] = "matAttrib";
+  attrib_map[kAttribMatName] = TestHelper::ConstructAttribute(
+      GL_FLOAT_MAT2,
+      1,
+      SH_PRECISION_MEDIUMP,
+      kAttribStaticUse,
+      kAttribMatName);
   // Check we can create shader.
   Shader* vshader = shader_manager_.CreateShader(
       kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
@@ -1106,15 +1152,15 @@
   TestHelper::SetShaderStates(
       gl_.get(), vshader, true, NULL, NULL, &attrib_map, NULL, NULL, NULL);
   // Check attrib infos got copied.
-  for (ShaderTranslator::VariableMap::const_iterator it = attrib_map.begin();
+  for (AttributeMap::const_iterator it = attrib_map.begin();
        it != attrib_map.end(); ++it) {
-    const Shader::VariableInfo* variable_info =
+    const sh::Attribute* variable_info =
         vshader->GetAttribInfo(it->first);
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
-    EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.arraySize, variable_info->arraySize);
     EXPECT_EQ(it->second.precision, variable_info->precision);
-    EXPECT_EQ(it->second.static_use, variable_info->static_use);
+    EXPECT_EQ(it->second.staticUse, variable_info->staticUse);
     EXPECT_EQ(it->second.name, variable_info->name);
   }
   TestHelper::SetShaderStates(
@@ -1134,19 +1180,40 @@
 
   program->SetAttribLocationBinding(kAttrib1Name, 0);
   EXPECT_FALSE(program->DetectAttribLocationBindingConflicts());
+  EXPECT_CALL(*(gl_.get()), BindAttribLocation(_, 0, _))
+      .Times(1)
+      .RetiresOnSaturation();
   EXPECT_TRUE(LinkAsExpected(program, true));
 
   program->SetAttribLocationBinding("xxx", 0);
   EXPECT_FALSE(program->DetectAttribLocationBindingConflicts());
+  EXPECT_CALL(*(gl_.get()), BindAttribLocation(_, 0, _))
+      .Times(1)
+      .RetiresOnSaturation();
   EXPECT_TRUE(LinkAsExpected(program, true));
 
   program->SetAttribLocationBinding(kAttrib2Name, 1);
   EXPECT_FALSE(program->DetectAttribLocationBindingConflicts());
+  EXPECT_CALL(*(gl_.get()), BindAttribLocation(_, _, _))
+      .Times(2)
+      .RetiresOnSaturation();
   EXPECT_TRUE(LinkAsExpected(program, true));
 
   program->SetAttribLocationBinding(kAttrib2Name, 0);
   EXPECT_TRUE(program->DetectAttribLocationBindingConflicts());
   EXPECT_TRUE(LinkAsExpected(program, false));
+
+  program->SetAttribLocationBinding(kAttribMatName, 1);
+  program->SetAttribLocationBinding(kAttrib2Name, 3);
+  EXPECT_CALL(*(gl_.get()), BindAttribLocation(_, _, _))
+      .Times(3)
+      .RetiresOnSaturation();
+  EXPECT_FALSE(program->DetectAttribLocationBindingConflicts());
+  EXPECT_TRUE(LinkAsExpected(program, true));
+
+  program->SetAttribLocationBinding(kAttrib2Name, 2);
+  EXPECT_TRUE(program->DetectAttribLocationBindingConflicts());
+  EXPECT_TRUE(LinkAsExpected(program, false));
 }
 
 TEST_F(ProgramManagerWithShaderTest, UniformsPrecisionMismatch) {
@@ -1156,12 +1223,12 @@
   const GLuint kFShaderClientId = 2;
   const GLuint kFShaderServiceId = 12;
 
-  ShaderTranslator::VariableMap vertex_uniform_map;
-  vertex_uniform_map["a"] = ShaderTranslator::VariableInfo(
-      1, 3, SH_PRECISION_MEDIUMP, 1, "a");
-  ShaderTranslator::VariableMap frag_uniform_map;
-  frag_uniform_map["a"] = ShaderTranslator::VariableInfo(
-      1, 3, SH_PRECISION_LOWP, 1, "a");
+  UniformMap vertex_uniform_map;
+  vertex_uniform_map["a"] = TestHelper::ConstructUniform(
+      GL_FLOAT, 3, GL_MEDIUM_FLOAT, true, "a");
+  UniformMap frag_uniform_map;
+  frag_uniform_map["a"] = TestHelper::ConstructUniform(
+      GL_FLOAT, 3, GL_LOW_FLOAT, true, "a");
 
   // Check we can create shader.
   Shader* vshader = shader_manager_.CreateShader(
@@ -1198,9 +1265,9 @@
 // shader, linking should fail.
 TEST_F(ProgramManagerWithShaderTest, VaryingTypeMismatch) {
   const VarInfo kVertexVarying =
-      { GL_FLOAT_VEC3, 1, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying };
+      { GL_FLOAT_VEC3, 1, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
   const VarInfo kFragmentVarying =
-      { GL_FLOAT_VEC4, 1, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying };
+      { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
   Program* program = SetupShaderVariableTest(
       &kVertexVarying, 1, &kFragmentVarying, 1);
 
@@ -1215,9 +1282,9 @@
 // shader, linking should fail.
 TEST_F(ProgramManagerWithShaderTest, VaryingArraySizeMismatch) {
   const VarInfo kVertexVarying =
-      { GL_FLOAT, 2, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying };
+      { GL_FLOAT, 2, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
   const VarInfo kFragmentVarying =
-      { GL_FLOAT, 3, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying };
+      { GL_FLOAT, 3, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
   Program* program = SetupShaderVariableTest(
       &kVertexVarying, 1, &kFragmentVarying, 1);
 
@@ -1232,9 +1299,9 @@
 // shader, linking should succeed.
 TEST_F(ProgramManagerWithShaderTest, VaryingPrecisionMismatch) {
   const VarInfo kVertexVarying =
-      { GL_FLOAT, 2, SH_PRECISION_HIGHP, 1, "a", kVarVarying };
+      { GL_FLOAT, 2, GL_HIGH_FLOAT, true, "a", kVarVarying };
   const VarInfo kFragmentVarying =
-      { GL_FLOAT, 2, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying };
+      { GL_FLOAT, 2, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
   Program* program = SetupShaderVariableTest(
       &kVertexVarying, 1, &kFragmentVarying, 1);
 
@@ -1249,7 +1316,7 @@
 // declared in vertex shader, link should fail.
 TEST_F(ProgramManagerWithShaderTest, VaryingMissing) {
   const VarInfo kFragmentVarying =
-      { GL_FLOAT, 3, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying };
+      { GL_FLOAT, 3, GL_MEDIUM_FLOAT, true, "a", kVarVarying };
   Program* program = SetupShaderVariableTest(
       NULL, 0, &kFragmentVarying, 1);
 
@@ -1265,7 +1332,7 @@
 // succeed.
 TEST_F(ProgramManagerWithShaderTest, InactiveVarying) {
   const VarInfo kFragmentVarying =
-      { GL_FLOAT, 3, SH_PRECISION_MEDIUMP, 0, "a", kVarVarying };
+      { GL_FLOAT, 3, GL_MEDIUM_FLOAT, false, "a", kVarVarying };
   Program* program = SetupShaderVariableTest(
       NULL, 0, &kFragmentVarying, 1);
 
@@ -1281,9 +1348,9 @@
 // failure.
 TEST_F(ProgramManagerWithShaderTest, AttribUniformNameConflict) {
   const VarInfo kVertexAttribute =
-      { GL_FLOAT_VEC4, 1, SH_PRECISION_MEDIUMP, 1, "a", kVarAttribute };
+      { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarAttribute };
   const VarInfo kFragmentUniform =
-      { GL_FLOAT_VEC4, 1, SH_PRECISION_MEDIUMP, 1, "a", kVarUniform };
+      { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarUniform };
   Program* program = SetupShaderVariableTest(
       &kVertexAttribute, 1, &kFragmentUniform, 1);
 
@@ -1297,12 +1364,12 @@
 // Varyings go over 8 rows.
 TEST_F(ProgramManagerWithShaderTest, TooManyVaryings) {
   const VarInfo kVertexVaryings[] = {
-      { GL_FLOAT_VEC4, 4, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying },
-      { GL_FLOAT_VEC4, 5, SH_PRECISION_MEDIUMP, 1, "b", kVarVarying }
+      { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, true, "a", kVarVarying },
+      { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
   const VarInfo kFragmentVaryings[] = {
-      { GL_FLOAT_VEC4, 4, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying },
-      { GL_FLOAT_VEC4, 5, SH_PRECISION_MEDIUMP, 1, "b", kVarVarying }
+      { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, true, "a", kVarVarying },
+      { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
   Program* program = SetupShaderVariableTest(
       kVertexVaryings, 2, kFragmentVaryings, 2);
@@ -1315,12 +1382,12 @@
 // Varyings go over 8 rows but some are inactive
 TEST_F(ProgramManagerWithShaderTest, TooManyInactiveVaryings) {
   const VarInfo kVertexVaryings[] = {
-      { GL_FLOAT_VEC4, 4, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying },
-      { GL_FLOAT_VEC4, 5, SH_PRECISION_MEDIUMP, 1, "b", kVarVarying }
+      { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, true, "a", kVarVarying },
+      { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
   const VarInfo kFragmentVaryings[] = {
-      { GL_FLOAT_VEC4, 4, SH_PRECISION_MEDIUMP, 0, "a", kVarVarying },
-      { GL_FLOAT_VEC4, 5, SH_PRECISION_MEDIUMP, 1, "b", kVarVarying }
+      { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, false, "a", kVarVarying },
+      { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
   Program* program = SetupShaderVariableTest(
       kVertexVaryings, 2, kFragmentVaryings, 2);
@@ -1334,12 +1401,12 @@
 // However, we still fail the check if kCountAll option is used.
 TEST_F(ProgramManagerWithShaderTest, CountAllVaryingsInPacking) {
   const VarInfo kVertexVaryings[] = {
-      { GL_FLOAT_VEC4, 4, SH_PRECISION_MEDIUMP, 1, "a", kVarVarying },
-      { GL_FLOAT_VEC4, 5, SH_PRECISION_MEDIUMP, 1, "b", kVarVarying }
+      { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, true, "a", kVarVarying },
+      { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
   const VarInfo kFragmentVaryings[] = {
-      { GL_FLOAT_VEC4, 4, SH_PRECISION_MEDIUMP, 0, "a", kVarVarying },
-      { GL_FLOAT_VEC4, 5, SH_PRECISION_MEDIUMP, 1, "b", kVarVarying }
+      { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, false, "a", kVarVarying },
+      { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying }
   };
   Program* program = SetupShaderVariableTest(
       kVertexVaryings, 2, kFragmentVaryings, 2);
@@ -1397,15 +1464,15 @@
         kUniform2FakeLocation,
         kUniform2RealLocation,
         kUniform2DesiredLocation,
-        kUniform2Name,
+        kUniform2NameWithArrayIndex,
       },
-      { kUniform3BadName,
+      { kUniform3Name,
         kUniform3Size,
         kUniform3Type,
         kUniform3FakeLocation,
         kUniform3RealLocation,
         kUniform3DesiredLocation,
-        kUniform3GoodName,
+        kUniform3NameWithArrayIndex,
       },
     };
     const size_t kNumAttribs = arraysize(kAttribs);
@@ -1447,7 +1514,7 @@
   EXPECT_TRUE(program->SetUniformLocationBinding(
       kUniform1Name, kUniform1DesiredLocation));
   EXPECT_TRUE(program->SetUniformLocationBinding(
-      kUniform3BadName, kUniform3DesiredLocation));
+      kUniform3Name, kUniform3DesiredLocation));
 
   static ProgramManagerWithShaderTest::AttribInfo kAttribs[] = {
     { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
@@ -1469,15 +1536,15 @@
       kUniform2FakeLocation,
       kUniform2RealLocation,
       kUniform2DesiredLocation,
-      kUniform2Name,
+      kUniform2NameWithArrayIndex,
     },
-    { kUniform3BadName,
+    { kUniform3Name,
       kUniform3Size,
       kUniform3Type,
       kUniform3FakeLocation,
       kUniform3RealLocation,
       kUniform3DesiredLocation,
-      kUniform3GoodName,
+      kUniform3NameWithArrayIndex,
     },
   };
 
@@ -1491,9 +1558,9 @@
   EXPECT_EQ(kUniform1DesiredLocation,
             program->GetUniformFakeLocation(kUniform1Name));
   EXPECT_EQ(kUniform3DesiredLocation,
-            program->GetUniformFakeLocation(kUniform3BadName));
+            program->GetUniformFakeLocation(kUniform3Name));
   EXPECT_EQ(kUniform3DesiredLocation,
-            program->GetUniformFakeLocation(kUniform3GoodName));
+            program->GetUniformFakeLocation(kUniform3NameWithArrayIndex));
 }
 
 class ProgramManagerWithCacheTest : public GpuServiceTest {
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index 189d78b..2707b90 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -12,6 +12,18 @@
 namespace gpu {
 namespace gles2 {
 
+namespace {
+
+// Given a variable name | a[0].b.c[0] |, return |a|.
+std::string GetTopVariableName(const std::string& fullname) {
+  size_t pos = fullname.find_first_of("[.");
+  if (pos == std::string::npos)
+    return fullname;
+  return fullname.substr(0, pos);
+}
+
+}  // namespace anonymous
+
 Shader::Shader(GLuint service_id, GLenum shader_type)
       : use_count_(0),
         service_id_(service_id),
@@ -96,15 +108,17 @@
   service_id_ = 0;
 }
 
-const Shader::VariableInfo* Shader::GetAttribInfo(
-    const std::string& name) const {
-  VariableMap::const_iterator it = attrib_map_.find(name);
+const sh::Attribute* Shader::GetAttribInfo(const std::string& name) const {
+  // Vertex attributes can't be arrays or structs (GLSL ES 3.00.4, section
+  // 4.3.4, "Input Variables"), so |name| is the top level name used as
+  // the AttributeMap key.
+  AttributeMap::const_iterator it = attrib_map_.find(name);
   return it != attrib_map_.end() ? &it->second : NULL;
 }
 
 const std::string* Shader::GetAttribMappedName(
     const std::string& original_name) const {
-  for (VariableMap::const_iterator it = attrib_map_.begin();
+  for (AttributeMap::const_iterator it = attrib_map_.begin();
        it != attrib_map_.end(); ++it) {
     if (it->second.name == original_name)
       return &(it->first);
@@ -120,15 +134,13 @@
   return NULL;
 }
 
-const Shader::VariableInfo* Shader::GetUniformInfo(
-    const std::string& name) const {
-  VariableMap::const_iterator it = uniform_map_.find(name);
+const sh::Uniform* Shader::GetUniformInfo(const std::string& name) const {
+  UniformMap::const_iterator it = uniform_map_.find(GetTopVariableName(name));
   return it != uniform_map_.end() ? &it->second : NULL;
 }
 
-const Shader::VariableInfo* Shader::GetVaryingInfo(
-    const std::string& name) const {
-  VariableMap::const_iterator it = varying_map_.find(name);
+const sh::Varying* Shader::GetVaryingInfo(const std::string& name) const {
+  VaryingMap::const_iterator it = varying_map_.find(GetTopVariableName(name));
   return it != varying_map_.end() ? &it->second : NULL;
 }
 
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h
index 359e574..c726767 100644
--- a/gpu/command_buffer/service/shader_manager.h
+++ b/gpu/command_buffer/service/shader_manager.h
@@ -29,8 +29,6 @@
     kGL,  // GL or GLES
   };
 
-  typedef ShaderTranslator::VariableInfo VariableInfo;
-
   void DoCompile(ShaderTranslatorInterface* translator,
                  TranslatedShaderSourceType type);
 
@@ -58,9 +56,9 @@
     return signature_source_;
   }
 
-  const VariableInfo* GetAttribInfo(const std::string& name) const;
-  const VariableInfo* GetUniformInfo(const std::string& name) const;
-  const VariableInfo* GetVaryingInfo(const std::string& name) const;
+  const sh::Attribute* GetAttribInfo(const std::string& name) const;
+  const sh::Uniform* GetUniformInfo(const std::string& name) const;
+  const sh::Varying* GetVaryingInfo(const std::string& name) const;
 
   // If the original_name is not found, return NULL.
   const std::string* GetAttribMappedName(
@@ -88,42 +86,39 @@
   }
 
   // Used by program cache.
-  const ShaderTranslator::VariableMap& attrib_map() const {
+  const AttributeMap& attrib_map() const {
     return attrib_map_;
   }
 
   // Used by program cache.
-  const ShaderTranslator::VariableMap& uniform_map() const {
+  const UniformMap& uniform_map() const {
     return uniform_map_;
   }
 
   // Used by program cache.
-  const ShaderTranslator::VariableMap& varying_map() const {
+  const VaryingMap& varying_map() const {
     return varying_map_;
   }
 
   // Used by program cache.
-  void set_attrib_map(const ShaderTranslator::VariableMap& attrib_map) {
+  void set_attrib_map(const AttributeMap& attrib_map) {
     // copied because cache might be cleared
-    attrib_map_ = ShaderTranslator::VariableMap(attrib_map);
+    attrib_map_ = AttributeMap(attrib_map);
   }
 
   // Used by program cache.
-  void set_uniform_map(const ShaderTranslator::VariableMap& uniform_map) {
+  void set_uniform_map(const UniformMap& uniform_map) {
     // copied because cache might be cleared
-    uniform_map_ = ShaderTranslator::VariableMap(uniform_map);
+    uniform_map_ = UniformMap(uniform_map);
   }
 
   // Used by program cache.
-  void set_varying_map(const ShaderTranslator::VariableMap& varying_map) {
+  void set_varying_map(const VaryingMap& varying_map) {
     // copied because cache might be cleared
-    varying_map_ = ShaderTranslator::VariableMap(varying_map);
+    varying_map_ = VaryingMap(varying_map);
   }
 
  private:
-  typedef ShaderTranslator::VariableMap VariableMap;
-  typedef ShaderTranslator::NameMap NameMap;
-
   friend class base::RefCounted<Shader>;
   friend class ShaderManager;
 
@@ -157,9 +152,9 @@
   std::string log_info_;
 
   // The type info when the shader was last compiled.
-  VariableMap attrib_map_;
-  VariableMap uniform_map_;
-  VariableMap varying_map_;
+  AttributeMap attrib_map_;
+  UniformMap uniform_map_;
+  VaryingMap varying_map_;
 
   // The name hashing info when the shader was last compiled.
   NameMap name_map_;
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc
index d6236f7..717572b 100644
--- a/gpu/command_buffer/service/shader_manager_unittest.cc
+++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -93,28 +93,28 @@
   const GLenum kShader1Type = GL_VERTEX_SHADER;
   const char* kClient1Source = "hello world";
   const GLenum kAttrib1Type = GL_FLOAT_VEC2;
-  const GLsizei kAttrib1Size = 2;
-  const int kAttrib1Precision = SH_PRECISION_MEDIUMP;
+  const GLint kAttrib1Size = 2;
+  const GLenum kAttrib1Precision = GL_MEDIUM_FLOAT;
   const char* kAttrib1Name = "attr1";
   const GLenum kAttrib2Type = GL_FLOAT_VEC3;
-  const GLsizei kAttrib2Size = 4;
-  const int kAttrib2Precision = SH_PRECISION_HIGHP;
+  const GLint kAttrib2Size = 4;
+  const GLenum kAttrib2Precision = GL_HIGH_FLOAT;
   const char* kAttrib2Name = "attr2";
-  const int kAttribStaticUse = 0;
+  const bool kAttribStaticUse = false;
   const GLenum kUniform1Type = GL_FLOAT_MAT2;
-  const GLsizei kUniform1Size = 3;
-  const int kUniform1Precision = SH_PRECISION_LOWP;
-  const int kUniform1StaticUse = 1;
+  const GLint kUniform1Size = 3;
+  const GLenum kUniform1Precision = GL_LOW_FLOAT;
+  const bool kUniform1StaticUse = true;
   const char* kUniform1Name = "uni1";
   const GLenum kUniform2Type = GL_FLOAT_MAT3;
-  const GLsizei kUniform2Size = 5;
-  const int kUniform2Precision = SH_PRECISION_MEDIUMP;
-  const int kUniform2StaticUse = 0;
+  const GLint kUniform2Size = 5;
+  const GLenum kUniform2Precision = GL_MEDIUM_FLOAT;
+  const bool kUniform2StaticUse = false;
   const char* kUniform2Name = "uni2";
   const GLenum kVarying1Type = GL_FLOAT_VEC4;
-  const GLsizei kVarying1Size = 1;
-  const int kVarying1Precision = SH_PRECISION_HIGHP;
-  const int kVarying1StaticUse = 0;
+  const GLint kVarying1Size = 1;
+  const GLenum kVarying1Precision = GL_HIGH_FLOAT;
+  const bool kVarying1StaticUse = false;
   const char* kVarying1Name = "varying1";
 
   // Check we can create shader.
@@ -145,22 +145,22 @@
   const std::string kLog = "foo";
   const std::string kTranslatedSource = "poo";
 
-  ShaderTranslator::VariableMap attrib_map;
-  attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo(
+  AttributeMap attrib_map;
+  attrib_map[kAttrib1Name] = TestHelper::ConstructAttribute(
       kAttrib1Type, kAttrib1Size, kAttrib1Precision,
       kAttribStaticUse, kAttrib1Name);
-  attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo(
+  attrib_map[kAttrib2Name] = TestHelper::ConstructAttribute(
       kAttrib2Type, kAttrib2Size, kAttrib2Precision,
       kAttribStaticUse, kAttrib2Name);
-  ShaderTranslator::VariableMap uniform_map;
-  uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo(
+  UniformMap uniform_map;
+  uniform_map[kUniform1Name] = TestHelper::ConstructUniform(
       kUniform1Type, kUniform1Size, kUniform1Precision,
       kUniform1StaticUse, kUniform1Name);
-  uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo(
+  uniform_map[kUniform2Name] = TestHelper::ConstructUniform(
       kUniform2Type, kUniform2Size, kUniform2Precision,
       kUniform2StaticUse, kUniform2Name);
-  ShaderTranslator::VariableMap varying_map;
-  varying_map[kVarying1Name] = ShaderTranslatorInterface::VariableInfo(
+  VaryingMap varying_map;
+  varying_map[kVarying1Name] = TestHelper::ConstructVarying(
       kVarying1Type, kVarying1Size, kVarying1Precision,
       kVarying1StaticUse, kVarying1Name);
 
@@ -175,41 +175,38 @@
 
   // Check varying infos got copied.
   EXPECT_EQ(attrib_map.size(), shader1->attrib_map().size());
-  for (ShaderTranslator::VariableMap::const_iterator it = attrib_map.begin();
+  for (AttributeMap::const_iterator it = attrib_map.begin();
        it != attrib_map.end(); ++it) {
-    const Shader::VariableInfo* variable_info =
-        shader1->GetAttribInfo(it->first);
+    const sh::Attribute* variable_info = shader1->GetAttribInfo(it->first);
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
-    EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.arraySize, variable_info->arraySize);
     EXPECT_EQ(it->second.precision, variable_info->precision);
-    EXPECT_EQ(it->second.static_use, variable_info->static_use);
+    EXPECT_EQ(it->second.staticUse, variable_info->staticUse);
     EXPECT_STREQ(it->second.name.c_str(), variable_info->name.c_str());
   }
   // Check uniform infos got copied.
   EXPECT_EQ(uniform_map.size(), shader1->uniform_map().size());
-  for (ShaderTranslator::VariableMap::const_iterator it = uniform_map.begin();
+  for (UniformMap::const_iterator it = uniform_map.begin();
        it != uniform_map.end(); ++it) {
-    const Shader::VariableInfo* variable_info =
-        shader1->GetUniformInfo(it->first);
+    const sh::Uniform* variable_info = shader1->GetUniformInfo(it->first);
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
-    EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.arraySize, variable_info->arraySize);
     EXPECT_EQ(it->second.precision, variable_info->precision);
-    EXPECT_EQ(it->second.static_use, variable_info->static_use);
+    EXPECT_EQ(it->second.staticUse, variable_info->staticUse);
     EXPECT_STREQ(it->second.name.c_str(), variable_info->name.c_str());
   }
   // Check varying infos got copied.
   EXPECT_EQ(varying_map.size(), shader1->varying_map().size());
-  for (ShaderTranslator::VariableMap::const_iterator it = varying_map.begin();
+  for (VaryingMap::const_iterator it = varying_map.begin();
        it != varying_map.end(); ++it) {
-    const Shader::VariableInfo* variable_info =
-        shader1->GetVaryingInfo(it->first);
+    const sh::Varying* variable_info = shader1->GetVaryingInfo(it->first);
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
-    EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.arraySize, variable_info->arraySize);
     EXPECT_EQ(it->second.precision, variable_info->precision);
-    EXPECT_EQ(it->second.static_use, variable_info->static_use);
+    EXPECT_EQ(it->second.staticUse, variable_info->staticUse);
     EXPECT_STREQ(it->second.name.c_str(), variable_info->name.c_str());
   }
 
diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc
index bc06ab3..0fdb4bc 100644
--- a/gpu/command_buffer/service/shader_translator.cc
+++ b/gpu/command_buffer/service/shader_translator.cc
@@ -14,9 +14,10 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 
-namespace {
+namespace gpu {
+namespace gles2 {
 
-using gpu::gles2::ShaderTranslator;
+namespace {
 
 class ShaderTranslatorInitializer {
  public:
@@ -34,58 +35,40 @@
 base::LazyInstance<ShaderTranslatorInitializer> g_translator_initializer =
     LAZY_INSTANCE_INITIALIZER;
 
-void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
-                     ShaderTranslator::VariableMap* var_map) {
+void GetAttributes(ShHandle compiler, AttributeMap* var_map) {
   if (!var_map)
     return;
   var_map->clear();
-
-  size_t name_len = 0, mapped_name_len = 0;
-  switch (var_type) {
-    case SH_ACTIVE_ATTRIBUTES:
-      ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &name_len);
-      break;
-    case SH_ACTIVE_UNIFORMS:
-      ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &name_len);
-      break;
-    case SH_VARYINGS:
-      ShGetInfo(compiler, SH_VARYING_MAX_LENGTH, &name_len);
-      break;
-    default: NOTREACHED();
-  }
-  ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_name_len);
-  if (name_len <= 1 || mapped_name_len <= 1) return;
-  scoped_ptr<char[]> name(new char[name_len]);
-  scoped_ptr<char[]> mapped_name(new char[mapped_name_len]);
-
-  size_t num_vars = 0;
-  ShGetInfo(compiler, var_type, &num_vars);
-  for (size_t i = 0; i < num_vars; ++i) {
-    size_t len = 0;
-    int size = 0;
-    sh::GLenum type = GL_NONE;
-    ShPrecisionType precision = SH_PRECISION_UNDEFINED;
-    int static_use = 0;
-
-    ShGetVariableInfo(compiler, var_type, i,
-                      &len, &size, &type, &precision, &static_use,
-                      name.get(), mapped_name.get());
-
-    // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
-    // to handle long struct field name mapping before we can do this.
-    // Also, we should modify the ANGLE interface to also return a length
-    // for mapped_name.
-    std::string name_string(name.get(), std::min(len, name_len - 1));
-    mapped_name.get()[mapped_name_len - 1] = '\0';
-
-    ShaderTranslator::VariableInfo info(
-        type, size, precision, static_use, name_string);
-    (*var_map)[mapped_name.get()] = info;
+  const std::vector<sh::Attribute>* attribs = ShGetAttributes(compiler);
+  if (attribs) {
+    for (size_t ii = 0; ii < attribs->size(); ++ii)
+      (*var_map)[(*attribs)[ii].mappedName] = (*attribs)[ii];
   }
 }
 
-void GetNameHashingInfo(
-    ShHandle compiler, ShaderTranslator::NameMap* name_map) {
+void GetUniforms(ShHandle compiler, UniformMap* var_map) {
+  if (!var_map)
+    return;
+  var_map->clear();
+  const std::vector<sh::Uniform>* uniforms = ShGetUniforms(compiler);
+  if (uniforms) {
+    for (size_t ii = 0; ii < uniforms->size(); ++ii)
+      (*var_map)[(*uniforms)[ii].mappedName] = (*uniforms)[ii];
+  }
+}
+
+void GetVaryings(ShHandle compiler, VaryingMap* var_map) {
+  if (!var_map)
+    return;
+  var_map->clear();
+  const std::vector<sh::Varying>* varyings = ShGetVaryings(compiler);
+  if (varyings) {
+    for (size_t ii = 0; ii < varyings->size(); ++ii)
+      (*var_map)[(*varyings)[ii].mappedName] = (*varyings)[ii];
+  }
+}
+
+void GetNameHashingInfo(ShHandle compiler, NameMap* name_map) {
   if (!name_map)
     return;
   name_map->clear();
@@ -110,9 +93,6 @@
 
 }  // namespace
 
-namespace gpu {
-namespace gles2 {
-
 ShaderTranslator::DestructionObserver::DestructionObserver() {
 }
 
@@ -167,9 +147,9 @@
 bool ShaderTranslator::Translate(const std::string& shader_source,
                                  std::string* info_log,
                                  std::string* translated_source,
-                                 VariableMap* attrib_map,
-                                 VariableMap* uniform_map,
-                                 VariableMap* varying_map,
+                                 AttributeMap* attrib_map,
+                                 UniformMap* uniform_map,
+                                 VaryingMap* varying_map,
                                  NameMap* name_map) const {
   // Make sure this instance is initialized.
   DCHECK(compiler_ != NULL);
@@ -194,9 +174,9 @@
       }
     }
     // Get info for attribs, uniforms, and varyings.
-    GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, attrib_map);
-    GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, uniform_map);
-    GetVariableInfo(compiler_, SH_VARYINGS, varying_map);
+    GetAttributes(compiler_, attrib_map);
+    GetUniforms(compiler_, uniform_map);
+    GetVaryings(compiler_, varying_map);
     // Get info for name hashing.
     GetNameHashingInfo(compiler_, name_map);
   }
diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h
index 57a198e..ff9d741 100644
--- a/gpu/command_buffer/service/shader_translator.h
+++ b/gpu/command_buffer/service/shader_translator.h
@@ -18,6 +18,13 @@
 namespace gpu {
 namespace gles2 {
 
+// Mapping between variable name and info.
+typedef base::hash_map<std::string, sh::Attribute> AttributeMap;
+typedef base::hash_map<std::string, sh::Uniform> UniformMap;
+typedef base::hash_map<std::string, sh::Varying> VaryingMap;
+// Mapping between hashed name and original name.
+typedef base::hash_map<std::string, std::string> NameMap;
+
 // Translates a GLSL ES 2.0 shader to desktop GLSL shader, or just
 // validates GLSL ES 2.0 shaders on a true GLSL ES implementation.
 class ShaderTranslatorInterface {
@@ -27,42 +34,6 @@
     kGlslES
   };
 
-  struct VariableInfo {
-    VariableInfo()
-        : type(0),
-          size(0),
-          precision(SH_PRECISION_UNDEFINED),
-          static_use(0) {
-    }
-
-    VariableInfo(int _type, int _size, int _precision,
-                 int _static_use, std::string _name)
-        : type(_type),
-          size(_size),
-          precision(_precision),
-          static_use(_static_use),
-          name(_name) {
-    }
-    bool operator==(
-        const ShaderTranslatorInterface::VariableInfo& other) const {
-      return type == other.type &&
-          size == other.size &&
-          precision == other.precision &&
-          strcmp(name.c_str(), other.name.c_str()) == 0;
-    }
-
-    int type;
-    int size;
-    int precision;
-    int static_use;
-    std::string name;  // name in the original shader source.
-  };
-
-  // Mapping between variable name and info.
-  typedef base::hash_map<std::string, VariableInfo> VariableMap;
-  // Mapping between hashed name and original name.
-  typedef base::hash_map<std::string, std::string> NameMap;
-
   // Initializes the translator.
   // Must be called once before using the translator object.
   virtual bool Init(
@@ -80,9 +51,9 @@
   virtual bool Translate(const std::string& shader_source,
                          std::string* info_log,
                          std::string* translated_shader,
-                         VariableMap* attrib_map,
-                         VariableMap* uniform_map,
-                         VariableMap* varying_map,
+                         AttributeMap* attrib_map,
+                         UniformMap* uniform_map,
+                         VaryingMap* varying_map,
                          NameMap* name_map) const = 0;
 
   // Return a string that is unique for a specfic set of options that would
@@ -123,9 +94,9 @@
   virtual bool Translate(const std::string& shader_source,
                          std::string* info_log,
                          std::string* translated_source,
-                         VariableMap* attrib_map,
-                         VariableMap* uniform_map,
-                         VariableMap* varying_map,
+                         AttributeMap* attrib_map,
+                         UniformMap* uniform_map,
+                         VaryingMap* varying_map,
                          NameMap* name_map) const override;
 
   virtual std::string GetStringForOptionsThatWouldAffectCompilation() const
diff --git a/gpu/command_buffer/service/shader_translator_unittest.cc b/gpu/command_buffer/service/shader_translator_unittest.cc
index f489626..198ea82 100644
--- a/gpu/command_buffer/service/shader_translator_unittest.cc
+++ b/gpu/command_buffer/service/shader_translator_unittest.cc
@@ -54,8 +54,10 @@
 
   // A valid shader should be successfully translated.
   std::string info_log, translated_source;
-  ShaderTranslatorInterface::VariableMap attrib_map, uniform_map, varying_map;
-  ShaderTranslatorInterface::NameMap name_map;
+  AttributeMap attrib_map;
+  UniformMap uniform_map;
+  VaryingMap varying_map;
+  NameMap name_map;
   EXPECT_TRUE(vertex_translator_->Translate(shader,
                                             &info_log,
                                             &translated_source,
@@ -84,8 +86,10 @@
 
   // An invalid shader should fail.
   std::string info_log, translated_source;
-  ShaderTranslatorInterface::VariableMap attrib_map, uniform_map, varying_map;
-  ShaderTranslatorInterface::NameMap name_map;
+  AttributeMap attrib_map;
+  UniformMap uniform_map;
+  VaryingMap varying_map;
+  NameMap name_map;
   EXPECT_FALSE(vertex_translator_->Translate(bad_shader,
                                              &info_log,
                                              &translated_source,
@@ -124,8 +128,10 @@
 
   // A valid shader should be successfully translated.
   std::string info_log, translated_source;
-  ShaderTranslatorInterface::VariableMap attrib_map, uniform_map, varying_map;
-  ShaderTranslatorInterface::NameMap name_map;
+  AttributeMap attrib_map;
+  UniformMap uniform_map;
+  VaryingMap varying_map;
+  NameMap name_map;
   EXPECT_TRUE(fragment_translator_->Translate(shader,
                                               &info_log,
                                               &translated_source,
@@ -148,8 +154,10 @@
   const char* shader = "foo-bar";
 
   std::string info_log, translated_source;
-  ShaderTranslatorInterface::VariableMap attrib_map, uniform_map, varying_map;
-  ShaderTranslatorInterface::NameMap name_map;
+  AttributeMap attrib_map;
+  UniformMap uniform_map;
+  VaryingMap varying_map;
+  NameMap name_map;
   // An invalid shader should fail.
   EXPECT_FALSE(fragment_translator_->Translate(shader,
                                                &info_log,
@@ -177,8 +185,10 @@
       "}";
 
   std::string info_log, translated_source;
-  ShaderTranslatorInterface::VariableMap attrib_map, uniform_map, varying_map;
-  ShaderTranslatorInterface::NameMap name_map;
+  AttributeMap attrib_map;
+  UniformMap uniform_map;
+  VaryingMap varying_map;
+  NameMap name_map;
   EXPECT_TRUE(vertex_translator_->Translate(shader,
                                             &info_log,
                                             &translated_source,
@@ -193,13 +203,12 @@
   // There should be no uniforms.
   EXPECT_TRUE(uniform_map.empty());
   // There should be one attribute with following characteristics:
-  // name:vPosition type:GL_FLOAT_VEC4 size:1.
+  // name:vPosition type:GL_FLOAT_VEC4 size:0.
   EXPECT_EQ(1u, attrib_map.size());
-  ShaderTranslator::VariableMap::const_iterator iter =
-      attrib_map.find("vPosition");
+  AttributeMap::const_iterator iter = attrib_map.find("vPosition");
   EXPECT_TRUE(iter != attrib_map.end());
-  EXPECT_EQ(GL_FLOAT_VEC4, iter->second.type);
-  EXPECT_EQ(1, iter->second.size);
+  EXPECT_EQ(static_cast<GLenum>(GL_FLOAT_VEC4), iter->second.type);
+  EXPECT_EQ(0u, iter->second.arraySize);
   EXPECT_EQ("vPosition", iter->second.name);
 }
 
@@ -218,8 +227,10 @@
       "}";
 
   std::string info_log, translated_source;
-  ShaderTranslatorInterface::VariableMap attrib_map, uniform_map, varying_map;
-  ShaderTranslatorInterface::NameMap name_map;
+  AttributeMap attrib_map;
+  UniformMap uniform_map;
+  VaryingMap varying_map;
+  NameMap name_map;
   EXPECT_TRUE(fragment_translator_->Translate(shader,
                                               &info_log,
                                               &translated_source,
@@ -236,20 +247,26 @@
   // There should be two uniforms with following characteristics:
   // 1. name:bar[0].foo.color[0] type:GL_FLOAT_VEC4 size:1
   // 2. name:bar[1].foo.color[0] type:GL_FLOAT_VEC4 size:1
-  EXPECT_EQ(2u, uniform_map.size());
+  // However, there will be only one entry "bar" in the map.
+  EXPECT_EQ(1u, uniform_map.size());
+  UniformMap::const_iterator iter = uniform_map.find("bar");
+  EXPECT_TRUE(iter != uniform_map.end());
   // First uniform.
-  ShaderTranslator::VariableMap::const_iterator iter =
-      uniform_map.find("bar[0].foo.color[0]");
-  EXPECT_TRUE(iter != uniform_map.end());
-  EXPECT_EQ(GL_FLOAT_VEC4, iter->second.type);
-  EXPECT_EQ(1, iter->second.size);
-  EXPECT_EQ("bar[0].foo.color[0]", iter->second.name);
+  const sh::ShaderVariable* info;
+  std::string original_name;
+  EXPECT_TRUE(iter->second.findInfoByMappedName(
+      "bar[0].foo.color[0]", &info, &original_name));
+  EXPECT_EQ(static_cast<GLenum>(GL_FLOAT_VEC4), info->type);
+  EXPECT_EQ(1u, info->arraySize);
+  EXPECT_STREQ("color", info->name.c_str());
+  EXPECT_STREQ("bar[0].foo.color[0]", original_name.c_str());
   // Second uniform.
-  iter = uniform_map.find("bar[1].foo.color[0]");
-  EXPECT_TRUE(iter != uniform_map.end());
-  EXPECT_EQ(GL_FLOAT_VEC4, iter->second.type);
-  EXPECT_EQ(1, iter->second.size);
-  EXPECT_EQ("bar[1].foo.color[0]", iter->second.name);
+  EXPECT_TRUE(iter->second.findInfoByMappedName(
+      "bar[1].foo.color[0]", &info, &original_name));
+  EXPECT_EQ(static_cast<GLenum>(GL_FLOAT_VEC4), info->type);
+  EXPECT_EQ(1u, info->arraySize);
+  EXPECT_STREQ("color", info->name.c_str());
+  EXPECT_STREQ("bar[1].foo.color[0]", original_name.c_str());
 }
 
 #if defined(OS_MACOSX)
@@ -263,8 +280,10 @@
       "}";
 
   std::string info_log, translated_source;
-  ShaderTranslatorInterface::VariableMap attrib_map, uniform_map, varying_map;
-  ShaderTranslatorInterface::NameMap name_map;
+  AttributeMap attrib_map;
+  UniformMap uniform_map;
+  VaryingMap varying_map;
+  NameMap name_map;
   EXPECT_TRUE(vertex_translator_->Translate(shader,
                                             &info_log,
                                             &translated_source,
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index 2f0e9c9..cea7b8a 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -34,6 +34,24 @@
 namespace gpu {
 namespace gles2 {
 
+namespace {
+
+template<typename T>
+T ConstructShaderVariable(
+    GLenum type, GLint array_size, GLenum precision,
+    bool static_use, const std::string& name) {
+  T var;
+  var.type = type;
+  var.arraySize = array_size;
+  var.precision = precision;
+  var.staticUse = static_use;
+  var.name = name;
+  var.mappedName = name;  // No name hashing.
+  return var;
+}
+
+}  // namespace anonymous
+
 // GCC requires these declarations, but MSVC requires they not be present
 #ifndef COMPILER_MSVC
 const GLuint TestHelper::kServiceBlackTexture2dId;
@@ -392,6 +410,17 @@
         .RetiresOnSaturation();
 #endif
   }
+
+  if (strstr(extensions, "GL_EXT_draw_buffers") ||
+      strstr(extensions, "GL_ARB_draw_buffers") ||
+      (is_es3 && strstr(extensions, "GL_NV_draw_buffers"))) {
+    EXPECT_CALL(*gl, GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, _))
+        .WillOnce(SetArgumentPointee<1>(8))
+        .RetiresOnSaturation();
+    EXPECT_CALL(*gl, GetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, _))
+        .WillOnce(SetArgumentPointee<1>(8))
+        .RetiresOnSaturation();
+  }
 }
 
 void TestHelper::SetupExpectationsForClearingUniforms(
@@ -648,10 +677,10 @@
       bool expected_valid,
       const std::string* const expected_log_info,
       const std::string* const expected_translated_source,
-      const ShaderTranslatorInterface::VariableMap* const expected_attrib_map,
-      const ShaderTranslatorInterface::VariableMap* const expected_uniform_map,
-      const ShaderTranslatorInterface::VariableMap* const expected_varying_map,
-      const ShaderTranslatorInterface::NameMap* const expected_name_map) {
+      const AttributeMap* const expected_attrib_map,
+      const UniformMap* const expected_uniform_map,
+      const VaryingMap* const expected_varying_map,
+      const NameMap* const expected_name_map) {
   const std::string empty_log_info;
   const std::string* log_info = (expected_log_info && !expected_valid) ?
       expected_log_info : &empty_log_info;
@@ -659,22 +688,18 @@
   const std::string* translated_source =
       (expected_translated_source && expected_valid) ?
           expected_translated_source : &empty_translated_source;
-  const ShaderTranslatorInterface::VariableMap empty_attrib_map;
-  const ShaderTranslatorInterface::VariableMap* attrib_map =
-      (expected_attrib_map && expected_valid) ?
-          expected_attrib_map : &empty_attrib_map;
-  const ShaderTranslatorInterface::VariableMap empty_uniform_map;
-  const ShaderTranslatorInterface::VariableMap* uniform_map =
-      (expected_uniform_map && expected_valid) ?
-          expected_uniform_map : &empty_uniform_map;
-  const ShaderTranslatorInterface::VariableMap empty_varying_map;
-  const ShaderTranslatorInterface::VariableMap* varying_map =
-      (expected_varying_map && expected_valid) ?
-          expected_varying_map : &empty_varying_map;
-  const ShaderTranslatorInterface::NameMap empty_name_map;
-  const ShaderTranslatorInterface::NameMap* name_map =
-      (expected_name_map && expected_valid) ?
-          expected_name_map : &empty_name_map;
+  const AttributeMap empty_attrib_map;
+  const AttributeMap* attrib_map = (expected_attrib_map && expected_valid) ?
+      expected_attrib_map : &empty_attrib_map;
+  const UniformMap empty_uniform_map;
+  const UniformMap* uniform_map = (expected_uniform_map && expected_valid) ?
+      expected_uniform_map : &empty_uniform_map;
+  const VaryingMap empty_varying_map;
+  const VaryingMap* varying_map = (expected_varying_map && expected_valid) ?
+      expected_varying_map : &empty_varying_map;
+  const NameMap empty_name_map;
+  const NameMap* name_map = (expected_name_map && expected_valid) ?
+      expected_name_map : &empty_name_map;
 
   MockShaderTranslator translator;
   EXPECT_CALL(translator, Translate(_,
@@ -714,6 +739,30 @@
   SetShaderStates(gl, shader, valid, NULL, NULL, NULL, NULL, NULL, NULL);
 }
 
+// static
+sh::Attribute TestHelper::ConstructAttribute(
+    GLenum type, GLint array_size, GLenum precision,
+    bool static_use, const std::string& name) {
+  return ConstructShaderVariable<sh::Attribute>(
+      type, array_size, precision, static_use, name);
+}
+
+// static
+sh::Uniform TestHelper::ConstructUniform(
+    GLenum type, GLint array_size, GLenum precision,
+    bool static_use, const std::string& name) {
+  return ConstructShaderVariable<sh::Uniform>(
+      type, array_size, precision, static_use, name);
+}
+
+// static
+sh::Varying TestHelper::ConstructVarying(
+    GLenum type, GLint array_size, GLenum precision,
+    bool static_use, const std::string& name) {
+  return ConstructShaderVariable<sh::Varying>(
+      type, array_size, precision, static_use, name);
+}
+
 ScopedGLImplementationSetter::ScopedGLImplementationSetter(
     gfx::GLImplementation implementation)
     : old_implementation_(gfx::GetGLImplementation()) {
diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h
index 92e929e..f83ed23 100644
--- a/gpu/command_buffer/service/test_helper.h
+++ b/gpu/command_buffer/service/test_helper.h
@@ -114,14 +114,24 @@
       bool expected_valid,
       const std::string* const expected_log_info,
       const std::string* const expected_translated_source,
-      const ShaderTranslatorInterface::VariableMap* const expected_attrib_map,
-      const ShaderTranslatorInterface::VariableMap* const expected_uniform_map,
-      const ShaderTranslatorInterface::VariableMap* const expected_varying_map,
-      const ShaderTranslatorInterface::NameMap* const expected_name_map);
+      const AttributeMap* const expected_attrib_map,
+      const UniformMap* const expected_uniform_map,
+      const VaryingMap* const expected_varying_map,
+      const NameMap* const expected_name_map);
 
   static void SetShaderStates(
       ::gfx::MockGLInterface* gl, Shader* shader, bool valid);
 
+  static sh::Attribute ConstructAttribute(
+      GLenum type, GLint array_size, GLenum precision,
+      bool static_use, const std::string& name);
+  static sh::Uniform ConstructUniform(
+      GLenum type, GLint array_size, GLenum precision,
+      bool static_use, const std::string& name);
+  static sh::Varying ConstructVarying(
+      GLenum type, GLint array_size, GLenum precision,
+      bool static_use, const std::string& name);
+
  private:
   static void SetupTextureInitializationExpectations(::gfx::MockGLInterface* gl,
                                                      GLenum target,
diff --git a/gpu/command_buffer/service/texture_definition.cc b/gpu/command_buffer/service/texture_definition.cc
index 8932ec2..6255a1c 100644
--- a/gpu/command_buffer/service/texture_definition.cc
+++ b/gpu/command_buffer/service/texture_definition.cc
@@ -374,21 +374,22 @@
       usage_(texture->usage()),
       immutable_(texture->IsImmutable()) {
   // TODO
-  DCHECK(!texture->level_infos_.empty());
-  DCHECK(!texture->level_infos_[0].empty());
+  DCHECK(!texture->face_infos_.empty());
+  DCHECK(!texture->face_infos_[0].level_infos.empty());
   DCHECK(!texture->NeedsMips());
-  DCHECK(texture->level_infos_[0][0].width);
-  DCHECK(texture->level_infos_[0][0].height);
+  DCHECK(texture->face_infos_[0].level_infos[0].width);
+  DCHECK(texture->face_infos_[0].level_infos[0].height);
 
+  const Texture::FaceInfo& first_face = texture->face_infos_[0];
   scoped_refptr<gfx::GLImage> gl_image(
       new GLImageSync(image_buffer_,
-                      gfx::Size(texture->level_infos_[0][0].width,
-                                texture->level_infos_[0][0].height)));
+                      gfx::Size(first_face.level_infos[0].width,
+                                first_face.level_infos[0].height)));
   texture->SetLevelImage(NULL, target, 0, gl_image.get());
 
   // TODO: all levels
   level_infos_.clear();
-  const Texture::LevelInfo& level = texture->level_infos_[0][0];
+  const Texture::LevelInfo& level = first_face.level_infos[0];
   LevelInfo info(level.target,
                  level.internal_format,
                  level.width,
@@ -435,13 +436,13 @@
   // though.
   glFlush();
 
-  texture->level_infos_.resize(1);
+  texture->face_infos_.resize(1);
   for (size_t i = 0; i < level_infos_.size(); i++) {
     const LevelInfo& base_info = level_infos_[i][0];
     const size_t levels_needed = TextureManager::ComputeMipMapCount(
         base_info.target, base_info.width, base_info.height, base_info.depth);
     DCHECK(level_infos_.size() <= levels_needed);
-    texture->level_infos_[0].resize(levels_needed);
+    texture->face_infos_[0].level_infos.resize(levels_needed);
     for (size_t n = 0; n < level_infos_.size(); n++) {
       const LevelInfo& info = level_infos_[i][n];
       texture->SetLevelInfo(NULL,
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index acc63d7..45aaa65 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -17,6 +17,7 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
+#include "ui/gl/gl_implementation.h"
 
 namespace gpu {
 namespace gles2 {
@@ -128,6 +129,7 @@
       service_id_(service_id),
       cleared_(true),
       num_uncleared_mips_(0),
+      num_npot_faces_(0),
       target_(0),
       min_filter_(GL_NEAREST_MIPMAP_LINEAR),
       mag_filter_(GL_LINEAR),
@@ -137,7 +139,11 @@
       pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
       max_level_set_(-1),
       texture_complete_(false),
+      texture_mips_dirty_(false),
+      texture_mips_complete_(false),
       cube_complete_(false),
+      texture_level0_dirty_(false),
+      texture_level0_complete_(false),
       npot_(false),
       has_been_bound_(false),
       framebuffer_attachment_count_(0),
@@ -220,16 +226,23 @@
 Texture::LevelInfo::~LevelInfo() {
 }
 
+Texture::FaceInfo::FaceInfo()
+    : num_mip_levels(0) {
+}
+
+Texture::FaceInfo::~FaceInfo() {
+}
+
 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
   if (target_ == 0)
     return CAN_RENDER_ALWAYS;
 
   if (target_ != GL_TEXTURE_EXTERNAL_OES) {
-    if (level_infos_.empty()) {
+    if (face_infos_.empty()) {
       return CAN_RENDER_NEVER;
     }
 
-    const Texture::LevelInfo& first_face = level_infos_[0][0];
+    const Texture::LevelInfo& first_face = face_infos_[0].level_infos[0];
     if (first_face.width == 0 ||
         first_face.height == 0 ||
         first_face.depth == 0) {
@@ -281,12 +294,12 @@
   DCHECK_GE(level, 0);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
   DCHECK_LT(static_cast<size_t>(face_index),
-            level_infos_.size());
+            face_infos_.size());
   DCHECK_LT(static_cast<size_t>(level),
-            level_infos_[face_index].size());
+            face_infos_[face_index].level_infos.size());
 
   const Texture::LevelInfo& info =
-      level_infos_[face_index][level];
+      face_infos_[face_index].level_infos[level];
 
   TextureSignature signature_data(target,
                                   level,
@@ -322,29 +335,30 @@
   if (!CanGenerateMipmaps(feature_info)) {
     return false;
   }
-  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
-    const Texture::LevelInfo& info1 = level_infos_[ii][0];
-    GLsizei width = info1.width;
-    GLsizei height = info1.height;
-    GLsizei depth = info1.depth;
+  for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
+    const Texture::FaceInfo& face_info = face_infos_[ii];
+    const Texture::LevelInfo& level0_info = face_info.level_infos[0];
+    GLsizei width = level0_info.width;
+    GLsizei height = level0_info.height;
+    GLsizei depth = level0_info.depth;
     GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
                                GLES2Util::IndexToGLFaceTarget(ii);
-    int num_mips =
-        TextureManager::ComputeMipMapCount(target_, width, height, depth);
-    for (int level = 1; level < num_mips; ++level) {
+
+    const GLsizei num_mips = face_info.num_mip_levels;
+    for (GLsizei level = 1; level < num_mips; ++level) {
       width = std::max(1, width >> 1);
       height = std::max(1, height >> 1);
       depth = std::max(1, depth >> 1);
       SetLevelInfo(feature_info,
                    target,
                    level,
-                   info1.internal_format,
+                   level0_info.internal_format,
                    width,
                    height,
                    depth,
-                   info1.border,
-                   info1.format,
-                   info1.type,
+                   level0_info.border,
+                   level0_info.format,
+                   level0_info.type,
                    true);
     }
   }
@@ -357,9 +371,9 @@
   DCHECK_EQ(0u, target_);  // you can only set this once.
   target_ = target;
   size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
-  level_infos_.resize(num_faces);
+  face_infos_.resize(num_faces);
   for (size_t ii = 0; ii < num_faces; ++ii) {
-    level_infos_[ii].resize(max_levels);
+    face_infos_[ii].level_infos.resize(max_levels);
   }
 
   if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
@@ -377,22 +391,22 @@
 bool Texture::CanGenerateMipmaps(
     const FeatureInfo* feature_info) const {
   if ((npot() && !feature_info->feature_flags().npot_ok) ||
-      level_infos_.empty() ||
+      face_infos_.empty() ||
       target_ == GL_TEXTURE_EXTERNAL_OES ||
       target_ == GL_TEXTURE_RECTANGLE_ARB) {
     return false;
   }
 
   // Can't generate mips for depth or stencil textures.
-  const Texture::LevelInfo& first = level_infos_[0][0];
+  const Texture::LevelInfo& first = face_infos_[0].level_infos[0];
   uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
   if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
     return false;
   }
 
   // TODO(gman): Check internal_format, format and type.
-  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
-    const LevelInfo& info = level_infos_[ii][0];
+  for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
+    const LevelInfo& info = face_infos_[ii].level_infos[0];
     if ((info.target == 0) || (info.width != first.width) ||
         (info.height != first.height) || (info.depth != 1) ||
         (info.format != first.format) ||
@@ -407,21 +421,74 @@
   return true;
 }
 
+bool Texture::TextureIsNPOT(GLsizei width,
+                            GLsizei height,
+                            GLsizei depth) {
+  return (GLES2Util::IsNPOT(width) ||
+          GLES2Util::IsNPOT(height) ||
+          GLES2Util::IsNPOT(depth));
+}
+
+bool Texture::TextureFaceComplete(const Texture::LevelInfo& first_face,
+                                  size_t face_index,
+                                  GLenum target,
+                                  GLenum internal_format,
+                                  GLsizei width,
+                                  GLsizei height,
+                                  GLsizei depth,
+                                  GLenum format,
+                                  GLenum type) {
+  bool complete = (target != 0 && depth == 1);
+  if (face_index != 0) {
+    complete &= (width == first_face.width &&
+                 height == first_face.height &&
+                 internal_format == first_face.internal_format &&
+                 format == first_face.format &&
+                 type == first_face.type);
+  }
+  return complete;
+}
+
+bool Texture::TextureMipComplete(const Texture::LevelInfo& level0_face,
+                                 GLenum target,
+                                 GLint level,
+                                 GLenum internal_format,
+                                 GLsizei width,
+                                 GLsizei height,
+                                 GLsizei depth,
+                                 GLenum format,
+                                 GLenum type) {
+  bool complete = (target != 0);
+  if (level != 0) {
+    const GLsizei mip_width = std::max(1, level0_face.width >> level);
+    const GLsizei mip_height = std::max(1, level0_face.height >> level);
+    const GLsizei mip_depth = std::max(1, level0_face.depth >> level);
+
+    complete &= (width == mip_width &&
+                 height == mip_height &&
+                 depth == mip_depth &&
+                 internal_format == level0_face.internal_format &&
+                 format == level0_face.format &&
+                 type == level0_face.type);
+  }
+  return complete;
+}
+
 void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
   DCHECK_GE(level, 0);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
   DCHECK_LT(static_cast<size_t>(face_index),
-            level_infos_.size());
+            face_infos_.size());
   DCHECK_LT(static_cast<size_t>(level),
-            level_infos_[face_index].size());
+            face_infos_[face_index].level_infos.size());
   Texture::LevelInfo& info =
-      level_infos_[face_index][level];
+      face_infos_[face_index].level_infos[level];
   UpdateMipCleared(&info, cleared);
   UpdateCleared();
 }
 
 void Texture::UpdateCleared() {
-  if (level_infos_.empty()) {
+  if (face_infos_.empty()) {
     return;
   }
 
@@ -466,13 +533,13 @@
 }
 
 void Texture::UpdateHasImages() {
-  if (level_infos_.empty())
+  if (face_infos_.empty())
     return;
 
   bool has_images = false;
-  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
-    for (size_t jj = 0; jj < level_infos_[ii].size(); ++jj) {
-      const Texture::LevelInfo& info = level_infos_[ii][jj];
+  for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
+    for (size_t jj = 0; jj < face_infos_[ii].level_infos.size(); ++jj) {
+      const Texture::LevelInfo& info = face_infos_[ii].level_infos[jj];
       if (info.image.get() != NULL) {
         has_images = true;
         break;
@@ -508,14 +575,44 @@
   DCHECK_GE(level, 0);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
   DCHECK_LT(static_cast<size_t>(face_index),
-            level_infos_.size());
+            face_infos_.size());
   DCHECK_LT(static_cast<size_t>(level),
-            level_infos_[face_index].size());
+            face_infos_[face_index].level_infos.size());
   DCHECK_GE(width, 0);
   DCHECK_GE(height, 0);
   DCHECK_GE(depth, 0);
   Texture::LevelInfo& info =
-      level_infos_[face_index][level];
+      face_infos_[face_index].level_infos[level];
+
+  // Update counters only if any attributes have changed. Counters are
+  // comparisons between the old and new values so it must be done before any
+  // assignment has been done to the LevelInfo.
+  if (info.target != target ||
+      info.internal_format != internal_format ||
+      info.width != width ||
+      info.height != height ||
+      info.depth != depth ||
+      info.format != format ||
+      info.type != type) {
+    if (level == 0) {
+      // Calculate the mip level count.
+      face_infos_[face_index].num_mip_levels =
+        TextureManager::ComputeMipMapCount(target_, width, height, depth);
+
+      // Update NPOT face count for the first level.
+      bool prev_npot = TextureIsNPOT(info.width, info.height, info.depth);
+      bool now_npot = TextureIsNPOT(width, height, depth);
+      if (prev_npot != now_npot)
+        num_npot_faces_ += now_npot ? 1 : -1;
+
+      // Signify that level 0 has been changed, so they need to be reverified.
+      texture_level0_dirty_ = true;
+    }
+
+    // Signify that at least one of the mips has changed.
+    texture_mips_dirty_ = true;
+  }
+
   info.target = target;
   info.level = level;
   info.internal_format = internal_format;
@@ -554,9 +651,9 @@
     GLsizei height,
     GLenum type) const {
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
-  if (level >= 0 && face_index < level_infos_.size() &&
-      static_cast<size_t>(level) < level_infos_[face_index].size()) {
-    const LevelInfo& info = level_infos_[face_index][level];
+  if (level >= 0 && face_index < face_infos_.size() &&
+      static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
+    const LevelInfo& info = face_infos_[face_index].level_infos[level];
     int32 right;
     int32 top;
     return SafeAddInt32(xoffset, width, &right) &&
@@ -575,9 +672,9 @@
   DCHECK(width);
   DCHECK(height);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
-  if (level >= 0 && face_index < level_infos_.size() &&
-      static_cast<size_t>(level) < level_infos_[face_index].size()) {
-    const LevelInfo& info = level_infos_[face_index][level];
+  if (level >= 0 && face_index < face_infos_.size() &&
+      static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
+    const LevelInfo& info = face_infos_[face_index].level_infos[level];
     if (info.target != 0) {
       *width = info.width;
       *height = info.height;
@@ -592,9 +689,9 @@
   DCHECK(type);
   DCHECK(internal_format);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
-  if (level >= 0 && face_index < level_infos_.size() &&
-      static_cast<size_t>(level) < level_infos_[face_index].size()) {
-    const LevelInfo& info = level_infos_[face_index][level];
+  if (level >= 0 && face_index < face_infos_.size() &&
+      static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
+    const LevelInfo& info = face_infos_[face_index].level_infos[level];
     if (info.target != 0) {
       *type = info.type;
       *internal_format = info.internal_format;
@@ -700,83 +797,85 @@
 void Texture::Update(const FeatureInfo* feature_info) {
   // Update npot status.
   // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
-  npot_ = target_ == GL_TEXTURE_EXTERNAL_OES;
+  npot_ = (target_ == GL_TEXTURE_EXTERNAL_OES) || (num_npot_faces_ > 0);
 
-  if (level_infos_.empty()) {
+  if (face_infos_.empty()) {
     texture_complete_ = false;
     cube_complete_ = false;
     return;
   }
 
-  // checks that the first mip of any face is npot.
-  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
-    const Texture::LevelInfo& info = level_infos_[ii][0];
-    if (GLES2Util::IsNPOT(info.width) ||
-        GLES2Util::IsNPOT(info.height) ||
-        GLES2Util::IsNPOT(info.depth)) {
-      npot_ = true;
-      break;
-    }
-  }
-
   // Update texture_complete and cube_complete status.
-  const Texture::LevelInfo& first_face = level_infos_[0][0];
-  int levels_needed = TextureManager::ComputeMipMapCount(
-      target_, first_face.width, first_face.height, first_face.depth);
+  const Texture::FaceInfo& first_face = face_infos_[0];
+  const Texture::LevelInfo& first_level = first_face.level_infos[0];
+  const GLsizei levels_needed = first_face.num_mip_levels;
+
   texture_complete_ =
       max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
-  cube_complete_ = (level_infos_.size() == 6) &&
-                   (first_face.width == first_face.height);
+  cube_complete_ = (face_infos_.size() == 6) &&
+                   (first_level.width == first_level.height);
 
-  if (first_face.width == 0 || first_face.height == 0) {
+  if (first_level.width == 0 || first_level.height == 0) {
     texture_complete_ = false;
-  }
-  if (first_face.type == GL_FLOAT &&
+  } else if (first_level.type == GL_FLOAT &&
       !feature_info->feature_flags().enable_texture_float_linear &&
       (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
        mag_filter_ != GL_NEAREST)) {
     texture_complete_ = false;
-  } else if (first_face.type == GL_HALF_FLOAT_OES &&
+  } else if (first_level.type == GL_HALF_FLOAT_OES &&
              !feature_info->feature_flags().enable_texture_half_float_linear &&
              (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
               mag_filter_ != GL_NEAREST)) {
     texture_complete_ = false;
   }
-  for (size_t ii = 0;
-       ii < level_infos_.size() && (cube_complete_ || texture_complete_);
-       ++ii) {
-    const Texture::LevelInfo& level0 = level_infos_[ii][0];
-    if (level0.target == 0 ||
-        level0.width != first_face.width ||
-        level0.height != first_face.height ||
-        level0.depth != 1 ||
-        level0.internal_format != first_face.internal_format ||
-        level0.format != first_face.format ||
-        level0.type != first_face.type) {
-      cube_complete_ = false;
-    }
-    // Get level0 dimensions
-    GLsizei width = level0.width;
-    GLsizei height = level0.height;
-    GLsizei depth = level0.depth;
-    for (GLint jj = 1; jj < levels_needed; ++jj) {
-      // compute required size for mip.
-      width = std::max(1, width >> 1);
-      height = std::max(1, height >> 1);
-      depth = std::max(1, depth >> 1);
-      const Texture::LevelInfo& info = level_infos_[ii][jj];
-      if (info.target == 0 ||
-          info.width != width ||
-          info.height != height ||
-          info.depth != depth ||
-          info.internal_format != level0.internal_format ||
-          info.format != level0.format ||
-          info.type != level0.type) {
-        texture_complete_ = false;
+
+  if (cube_complete_ && texture_level0_dirty_) {
+    texture_level0_complete_ = true;
+    for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
+      const Texture::LevelInfo& level0 = face_infos_[ii].level_infos[0];
+      if (!TextureFaceComplete(first_level,
+                               ii,
+                               level0.target,
+                               level0.internal_format,
+                               level0.width,
+                               level0.height,
+                               level0.depth,
+                               level0.format,
+                               level0.type)) {
+        texture_level0_complete_ = false;
         break;
       }
     }
+    texture_level0_dirty_ = false;
   }
+  cube_complete_ &= texture_level0_complete_;
+
+  if (texture_complete_ && texture_mips_dirty_) {
+    texture_mips_complete_ = true;
+    for (size_t ii = 0;
+         ii < face_infos_.size() && texture_mips_complete_;
+         ++ii) {
+      const Texture::FaceInfo& face_info = face_infos_[ii];
+      const Texture::LevelInfo& level0 = face_info.level_infos[0];
+      for (GLsizei jj = 1; jj < levels_needed; ++jj) {
+        const Texture::LevelInfo& level_info = face_infos_[ii].level_infos[jj];
+        if (!TextureMipComplete(level0,
+                                level_info.target,
+                                jj,
+                                level_info.internal_format,
+                                level_info.width,
+                                level_info.height,
+                                level_info.depth,
+                                level_info.format,
+                                level_info.type)) {
+          texture_mips_complete_ = false;
+          break;
+        }
+      }
+    }
+    texture_mips_dirty_ = false;
+  }
+  texture_complete_ &= texture_mips_complete_;
 }
 
 bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
@@ -785,13 +884,10 @@
     return true;
   }
 
-  const Texture::LevelInfo& first_face = level_infos_[0][0];
-  int levels_needed = TextureManager::ComputeMipMapCount(
-      target_, first_face.width, first_face.height, first_face.depth);
-
-  for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
-    for (GLint jj = 0; jj < levels_needed; ++jj) {
-      Texture::LevelInfo& info = level_infos_[ii][jj];
+  for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
+    const Texture::FaceInfo& face_info = face_infos_[ii];
+    for (GLint jj = 0; jj < face_info.num_mip_levels; ++jj) {
+      const Texture::LevelInfo& info = face_info.level_infos[jj];
       if (info.target != 0) {
         if (!ClearLevel(decoder, info.target, jj)) {
           return false;
@@ -805,12 +901,12 @@
 
 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
-  if (face_index >= level_infos_.size() ||
-      level >= static_cast<GLint>(level_infos_[face_index].size())) {
+  if (face_index >= face_infos_.size() ||
+      level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
     return true;
   }
 
-  const Texture::LevelInfo& info = level_infos_[face_index][level];
+  const Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
 
   return info.cleared;
 }
@@ -827,12 +923,12 @@
     GLES2Decoder* decoder, GLenum target, GLint level) {
   DCHECK(decoder);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
-  if (face_index >= level_infos_.size() ||
-      level >= static_cast<GLint>(level_infos_[face_index].size())) {
+  if (face_index >= face_infos_.size() ||
+      level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
     return true;
   }
 
-  Texture::LevelInfo& info = level_infos_[face_index][level];
+  Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
 
   DCHECK(target == info.target);
 
@@ -862,11 +958,11 @@
   DCHECK_GE(level, 0);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
   DCHECK_LT(static_cast<size_t>(face_index),
-            level_infos_.size());
+            face_infos_.size());
   DCHECK_LT(static_cast<size_t>(level),
-            level_infos_[face_index].size());
+            face_infos_[face_index].level_infos.size());
   Texture::LevelInfo& info =
-      level_infos_[face_index][level];
+      face_infos_[face_index].level_infos[level];
   DCHECK_EQ(info.target, target);
   DCHECK_EQ(info.level, level);
   info.image = image;
@@ -881,9 +977,9 @@
   }
 
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
-  if (level >= 0 && face_index < level_infos_.size() &&
-      static_cast<size_t>(level) < level_infos_[face_index].size()) {
-    const LevelInfo& info = level_infos_[face_index][level];
+  if (level >= 0 && face_index < face_infos_.size() &&
+      static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
+    const LevelInfo& info = face_infos_[face_index].level_infos[level];
     if (info.target != 0) {
       return info.image.get();
     }
@@ -1545,6 +1641,18 @@
                texture_ref, args);
 }
 
+GLenum TextureManager::AdjustTexFormat(GLenum format) const {
+  // TODO: GLES 3 allows for internal format and format to differ. This logic
+  // may need to change as a result.
+  if (gfx::GetGLImplementation() == gfx::kGLImplementationDesktopGL) {
+    if (format == GL_SRGB_EXT)
+      return GL_RGB;
+    if (format == GL_SRGB_ALPHA_EXT)
+      return GL_RGBA;
+  }
+  return format;
+}
+
 void TextureManager::DoTexImage2D(
     DecoderTextureState* texture_state,
     ErrorState* error_state,
@@ -1581,7 +1689,7 @@
     {
       ScopedTextureUploadTimer timer(texture_state);
       glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
-                      args.format, args.type, args.pixels);
+                      AdjustTexFormat(args.format), args.type, args.pixels);
     }
     SetLevelCleared(texture_ref, args.target, args.level, true);
     texture_state->tex_image_2d_failed = false;
@@ -1593,7 +1701,7 @@
     ScopedTextureUploadTimer timer(texture_state);
     glTexImage2D(
         args.target, args.level, args.internal_format, args.width, args.height,
-        args.border, args.format, args.type, args.pixels);
+        args.border, AdjustTexFormat(args.format), args.type, args.pixels);
   }
   GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
   if (error == GL_NO_ERROR) {
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index df00607..25bc2ff 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -208,6 +208,14 @@
     uint32 estimated_size;
   };
 
+  struct FaceInfo {
+    FaceInfo();
+    ~FaceInfo();
+
+    GLsizei num_mip_levels;
+    std::vector<LevelInfo> level_infos;
+  };
+
   // Set the info for a particular level.
   void SetLevelInfo(
       const FeatureInfo* feature_info,
@@ -276,6 +284,31 @@
   // Returns true if mipmaps can be generated by GL.
   bool CanGenerateMipmaps(const FeatureInfo* feature_info) const;
 
+  // Returns true if any of the texture dimensions are not a power of two.
+  static bool TextureIsNPOT(GLsizei width, GLsizei height, GLsizei depth);
+
+  // Returns true if texture face is complete relative to the first face.
+  static bool TextureFaceComplete(const Texture::LevelInfo& first_face,
+                                  size_t face_index,
+                                  GLenum target,
+                                  GLenum internal_format,
+                                  GLsizei width,
+                                  GLsizei height,
+                                  GLsizei depth,
+                                  GLenum format,
+                                  GLenum type);
+
+  // Returns true if texture mip level is complete relative to first level.
+  static bool TextureMipComplete(const Texture::LevelInfo& level0_face,
+                                 GLenum target,
+                                 GLint level,
+                                 GLenum internal_format,
+                                 GLsizei width,
+                                 GLsizei height,
+                                 GLsizei depth,
+                                 GLenum format,
+                                 GLenum type);
+
   // Sets the Texture's target
   // Parameters:
   //   target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP or
@@ -327,7 +360,7 @@
   MailboxManager* mailbox_manager_;
 
   // Info about each face and level of texture.
-  std::vector<std::vector<LevelInfo> > level_infos_;
+  std::vector<FaceInfo> face_infos_;
 
   // The texture refs that point to this Texture.
   typedef std::set<TextureRef*> RefSet;
@@ -344,6 +377,7 @@
   bool cleared_;
 
   int num_uncleared_mips_;
+  int num_npot_faces_;
 
   // The target. 0 if unset, otherwise GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
   GLenum target_;
@@ -362,9 +396,17 @@
   // Whether or not this texture is "texture complete"
   bool texture_complete_;
 
+  // Whether mip levels have changed and should be reverified.
+  bool texture_mips_dirty_;
+  bool texture_mips_complete_;
+
   // Whether or not this texture is "cube complete"
   bool cube_complete_;
 
+  // Whether any level 0 faces have changed and should be reverified.
+  bool texture_level0_dirty_;
+  bool texture_level0_complete_;
+
   // Whether or not this texture is non-power-of-two
   bool npot_;
 
@@ -772,6 +814,8 @@
   void UpdateNumImages(int delta);
   void IncFramebufferStateChangeCount();
 
+  GLenum AdjustTexFormat(GLenum format) const;
+
   MemoryTypeTracker* GetMemTracker(GLenum texture_pool);
   scoped_ptr<MemoryTypeTracker> memory_tracker_managed_;
   scoped_ptr<MemoryTypeTracker> memory_tracker_unmanaged_;
diff --git a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
index c73cc3d..745ceb9 100644
--- a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
+++ b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
@@ -17,6 +17,7 @@
 #include "gpu/command_buffer/tests/gl_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gl/gl_image.h"
 
 using testing::_;
@@ -73,14 +74,11 @@
 TEST_F(GpuMemoryBufferTest, Lifecycle) {
   uint8 pixels[1 * 4] = { 255u, 0u, 0u, 255u };
 
-  // Create the image. This should add the image ID to the ImageManager.
-  GLuint image_id = glCreateImageCHROMIUM(
-      kImageWidth, kImageHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM);
-  EXPECT_NE(0u, image_id);
-  EXPECT_TRUE(gl_.decoder()->GetImageManager()->LookupImage(image_id) != NULL);
+  scoped_ptr<gfx::GpuMemoryBuffer> buffer(gl_.CreateGpuMemoryBuffer(
+      gfx::Size(kImageWidth, kImageHeight), gfx::GpuMemoryBuffer::RGBA_8888));
 
-  // Map image for writing.
-  uint8* mapped_buffer = static_cast<uint8*>(glMapImageCHROMIUM(image_id));
+  // Map buffer for writing.
+  uint8* mapped_buffer = static_cast<uint8*>(buffer->Map());
   ASSERT_TRUE(mapped_buffer != NULL);
 
   // Assign a value to each pixel.
@@ -94,8 +92,14 @@
     }
   }
 
-  // Unmap the image.
-  glUnmapImageCHROMIUM(image_id);
+  // Unmap the buffer.
+  buffer->Unmap();
+
+  // Create the image. This should add the image ID to the ImageManager.
+  GLuint image_id = glCreateImageCHROMIUM(
+      buffer->AsClientBuffer(), kImageWidth, kImageHeight, GL_RGBA);
+  EXPECT_NE(0u, image_id);
+  EXPECT_TRUE(gl_.decoder()->GetImageManager()->LookupImage(image_id) != NULL);
 
   // Bind the texture and the image.
   glBindTexture(GL_TEXTURE_2D, texture_ids_[0]);
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 2a837eb..5678778 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -6,6 +6,7 @@
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
 
 #include <vector>
 
@@ -35,25 +36,30 @@
 namespace gpu {
 namespace {
 
-int BytesPerPixel(unsigned internalformat) {
-  switch (internalformat) {
-    case GL_RGBA8_OES:
+size_t BytesPerPixel(gfx::GpuMemoryBuffer::Format format) {
+  switch (format) {
+    case gfx::GpuMemoryBuffer::RGBA_8888:
+    case gfx::GpuMemoryBuffer::BGRA_8888:
       return 4;
-    default:
+    case gfx::GpuMemoryBuffer::RGBX_8888:
       NOTREACHED();
       return 0;
   }
+
+  NOTREACHED();
+  return 0;
 }
 
 class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
  public:
   GpuMemoryBufferImpl(base::RefCountedBytes* bytes,
                       const gfx::Size& size,
-                      unsigned internalformat)
-      : bytes_(bytes),
-        size_(size),
-        internalformat_(internalformat),
-        mapped_(false) {}
+                      gfx::GpuMemoryBuffer::Format format)
+      : bytes_(bytes), size_(size), format_(format), mapped_(false) {}
+
+  static GpuMemoryBufferImpl* FromClientBuffer(ClientBuffer buffer) {
+    return reinterpret_cast<GpuMemoryBufferImpl*>(buffer);
+  }
 
   // Overridden from gfx::GpuMemoryBuffer:
   virtual void* Map() override {
@@ -62,18 +68,24 @@
   }
   virtual void Unmap() override { mapped_ = false; }
   virtual bool IsMapped() const override { return mapped_; }
+  virtual Format GetFormat() const override { return format_; }
   virtual uint32 GetStride() const override {
-    return size_.width() * BytesPerPixel(internalformat_);
+    return size_.width() * BytesPerPixel(format_);
   }
   virtual gfx::GpuMemoryBufferHandle GetHandle() const override {
     NOTREACHED();
     return gfx::GpuMemoryBufferHandle();
   }
+  virtual ClientBuffer AsClientBuffer() override {
+    return reinterpret_cast<ClientBuffer>(this);
+  }
+
+  base::RefCountedBytes* bytes() { return bytes_.get(); }
 
  private:
   scoped_refptr<base::RefCountedBytes> bytes_;
   const gfx::Size size_;
-  unsigned internalformat_;
+  gfx::GpuMemoryBuffer::Format format_;
   bool mapped_;
 };
 
@@ -116,6 +128,16 @@
   }
 }
 
+// static
+scoped_ptr<gfx::GpuMemoryBuffer> GLManager::CreateGpuMemoryBuffer(
+    const gfx::Size& size,
+    gfx::GpuMemoryBuffer::Format format) {
+  std::vector<unsigned char> data(size.GetArea() * BytesPerPixel(format), 0);
+  scoped_refptr<base::RefCountedBytes> bytes(new base::RefCountedBytes(data));
+  return make_scoped_ptr<gfx::GpuMemoryBuffer>(
+      new GpuMemoryBufferImpl(bytes.get(), size, format));
+}
+
 void GLManager::Initialize(const GLManager::Options& options) {
   const int32 kCommandBufferSize = 1024 * 1024;
   const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
@@ -315,45 +337,44 @@
   return decoder_->GetCapabilities();
 }
 
-gfx::GpuMemoryBuffer* GLManager::CreateGpuMemoryBuffer(
-    size_t width,
-    size_t height,
-    unsigned internalformat,
-    unsigned usage,
-    int32* id) {
-  gfx::Size size(width, height);
+int32 GLManager::CreateImage(ClientBuffer buffer,
+                             size_t width,
+                             size_t height,
+                             unsigned internalformat) {
+  GpuMemoryBufferImpl* gpu_memory_buffer =
+      GpuMemoryBufferImpl::FromClientBuffer(buffer);
 
-  *id = -1;
-
-  std::vector<unsigned char> data(
-      size.GetArea() * BytesPerPixel(internalformat), 0);
-  scoped_refptr<base::RefCountedBytes> bytes(new base::RefCountedBytes(data));
-  scoped_ptr<gfx::GpuMemoryBuffer> buffer(
-      new GpuMemoryBufferImpl(bytes.get(), size, internalformat));
+  scoped_refptr<gfx::GLImageRefCountedMemory> image(
+      new gfx::GLImageRefCountedMemory(gfx::Size(width, height),
+                                       internalformat));
+  if (!image->Initialize(gpu_memory_buffer->bytes(),
+                         gpu_memory_buffer->GetFormat())) {
+    return -1;
+  }
 
   static int32 next_id = 1;
   int32 new_id = next_id++;
 
-  scoped_refptr<gfx::GLImageRefCountedMemory> image(
-      new gfx::GLImageRefCountedMemory(size, internalformat));
-  if (!image->Initialize(bytes.get()))
-    return NULL;
-
   gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
   DCHECK(image_manager);
   image_manager->AddImage(image.get(), new_id);
-
-  *id = new_id;
-  DCHECK(gpu_memory_buffers_.find(new_id) == gpu_memory_buffers_.end());
-  return gpu_memory_buffers_.add(new_id, buffer.Pass()).first->second;
+  return new_id;
 }
 
-void GLManager::DestroyGpuMemoryBuffer(int32 id) {
+int32 GLManager::CreateGpuMemoryBufferImage(size_t width,
+                                            size_t height,
+                                            unsigned internalformat,
+                                            unsigned usage) {
+  DCHECK_EQ(usage, static_cast<unsigned>(GL_MAP_CHROMIUM));
+  scoped_ptr<gfx::GpuMemoryBuffer> buffer = GLManager::CreateGpuMemoryBuffer(
+      gfx::Size(width, height), gfx::GpuMemoryBuffer::RGBA_8888);
+  return CreateImage(buffer->AsClientBuffer(), width, height, internalformat);
+}
+
+void GLManager::DestroyImage(int32 id) {
   gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
   DCHECK(image_manager);
   image_manager->RemoveImage(id);
-
-  gpu_memory_buffers_.erase(id);
 }
 
 uint32 GLManager::InsertSyncPoint() {
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index a4f4c71..d76ca5b 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -10,6 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "gpu/command_buffer/client/gpu_control.h"
 #include "gpu/command_buffer/service/feature_info.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/size.h"
 
 namespace gfx {
@@ -60,6 +61,10 @@
   GLManager();
   virtual ~GLManager();
 
+  static scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
+      const gfx::Size& size,
+      gfx::GpuMemoryBuffer::Format format);
+
   void Initialize(const Options& options);
   void Destroy();
 
@@ -91,12 +96,15 @@
 
   // GpuControl implementation.
   virtual Capabilities GetCapabilities() override;
-  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(size_t width,
-                                                      size_t height,
-                                                      unsigned internalformat,
-                                                      unsigned usage,
-                                                      int32* id) override;
-  virtual void DestroyGpuMemoryBuffer(int32 id) override;
+  virtual int32 CreateImage(ClientBuffer buffer,
+                            size_t width,
+                            size_t height,
+                            unsigned internalformat) override;
+  virtual void DestroyImage(int32 id) override;
+  virtual int32 CreateGpuMemoryBufferImage(size_t width,
+                                           size_t height,
+                                           unsigned internalformat,
+                                           unsigned usage) override;
   virtual uint32 InsertSyncPoint() override;
   virtual uint32 InsertFutureSyncPoint() override;
   virtual void RetireSyncPoint(uint32 sync_point) override;
@@ -124,9 +132,6 @@
   scoped_ptr<gles2::GLES2Implementation> gles2_implementation_;
   bool context_lost_allowed_;
 
-  // Client GpuControl implementation.
-  base::ScopedPtrHashMap<int32, gfx::GpuMemoryBuffer> gpu_memory_buffers_;
-
   // Used on Android to virtualize GL for all contexts.
   static int use_count_;
   static scoped_refptr<gfx::GLShareGroup>* base_share_group_;
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index d38e1eb..c9b5335 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "7.5",
+  "version": "7.7",
   "entries": [
     {
       "id": 1,
@@ -824,18 +824,6 @@
         "use_virtualized_gl_contexts"
       ]
     },
-    {
-      "id": 73,
-      "description": "Using D3D11 causes browser crashes on certain Intel GPUs",
-      "cr_bugs": [310808],
-      "os": {
-        "type": "win"
-      },
-      "vendor_id": "0x8086",
-      "features": [
-        "disable_d3d11"
-      ]
-    },
 )  // LONG_STRING_CONST macro
 // Avoid C2026 (string too big) error on VisualStudio.
 LONG_STRING_CONST(
@@ -1024,6 +1012,40 @@
       "features": [
         "etc1_power_of_two_only"
       ]
+    },
+    {
+      "id": 92,
+      "description": "Old Intel drivers cannot reliably support D3D11",
+      "cr_bugs": [363721],
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x8086",
+      "driver_version": {
+        "op": "<",
+        "value": "8.16"
+      },
+      "features": [
+        "disable_d3d11"
+      ]
+    },
+    {
+      "id": 93,
+      "description": "The GL implementation on the Android emulator has problems with PBOs.",
+      "cr_bugs": [340882],
+      "os": {
+        "type": "android"
+      },
+      "gl_vendor": "VMware.*",
+      "gl_renderer": "Gallium.*",
+      "gl_type": "gles",
+      "gl_version": {
+        "op": "=",
+        "value": "3.0"
+      },
+      "features": [
+        "disable_async_readpixels"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc
index f560dcb..c7951f9 100644
--- a/gpu/config/gpu_info.cc
+++ b/gpu/config/gpu_info.cc
@@ -17,6 +17,19 @@
   enumerator->EndGPUDevice();
 }
 
+void EnumerateVideoEncodeAcceleratorSupportedProfile(
+    gpu::GPUInfo::Enumerator* enumerator,
+    const media::VideoEncodeAccelerator::SupportedProfile profile) {
+  enumerator->BeginVideoEncodeAcceleratorSupportedProfile();
+  enumerator->AddInt("profile", profile.profile);
+  enumerator->AddInt("maxResolutionWidth", profile.max_resolution.width());
+  enumerator->AddInt("maxResolutionHeight", profile.max_resolution.height());
+  enumerator->AddInt("maxFramerateNumerator", profile.max_framerate_numerator);
+  enumerator->AddInt("maxFramerateDenominator",
+                     profile.max_framerate_denominator);
+  enumerator->EndVideoEncodeAcceleratorSupportedProfile();
+}
+
 }  // namespace
 
 namespace gpu {
@@ -88,6 +101,8 @@
     CollectInfoResult dx_diagnostics_info_state;
     DxDiagNode dx_diagnostics;
 #endif
+    std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+        video_encode_accelerator_supported_profiles;
   };
 
   // If this assert fails then most likely something below needs to be updated.
@@ -142,6 +157,12 @@
 #if defined(OS_WIN)
   enumerator->AddInt("DxDiagnosticsInfoState", dx_diagnostics_info_state);
 #endif
+  // TODO(kbr): add dx_diagnostics on Windows.
+  for (size_t ii = 0; ii < video_encode_accelerator_supported_profiles.size();
+       ++ii) {
+    EnumerateVideoEncodeAcceleratorSupportedProfile(
+        enumerator, video_encode_accelerator_supported_profiles[ii]);
+  }
   enumerator->EndAuxAttributes();
 }
 
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index 8f5479b..bdbb205 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -18,6 +18,7 @@
 #include "gpu/config/dx_diag_node.h"
 #include "gpu/config/gpu_performance_stats.h"
 #include "gpu/gpu_export.h"
+#include "media/video/video_encode_accelerator.h"
 
 namespace gpu {
 
@@ -177,6 +178,8 @@
   DxDiagNode dx_diagnostics;
 #endif
 
+  std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+      video_encode_accelerator_supported_profiles;
   // Note: when adding new members, please remember to update EnumerateFields
   // in gpu_info.cc.
 
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index 78dfe22..5d25546 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -156,6 +156,8 @@
   basic_gpu_info->direct_rendering = context_gpu_info.direct_rendering;
   basic_gpu_info->context_info_state = context_gpu_info.context_info_state;
   basic_gpu_info->initialization_time = context_gpu_info.initialization_time;
+  basic_gpu_info->video_encode_accelerator_supported_profiles =
+      context_gpu_info.video_encode_accelerator_supported_profiles;
 }
 
 }  // namespace gpu
diff --git a/gpu/config/gpu_info_unittest.cc b/gpu/config/gpu_info_unittest.cc
index 48d476f..71d4e5c 100644
--- a/gpu/config/gpu_info_unittest.cc
+++ b/gpu/config/gpu_info_unittest.cc
@@ -32,6 +32,7 @@
 #if defined(OS_WIN)
   EXPECT_EQ(gpu_info.dx_diagnostics_info_state, kCollectInfoNone);
 #endif
+  EXPECT_EQ(gpu_info.video_encode_accelerator_supported_profiles.size(), 0u);
 }
 
 }  // namespace gpu
diff --git a/gpu/config/software_rendering_list_json.cc b/gpu/config/software_rendering_list_json.cc
index 99496ae..c7c7f03 100644
--- a/gpu/config/software_rendering_list_json.cc
+++ b/gpu/config/software_rendering_list_json.cc
@@ -18,7 +18,7 @@
 {
   "name": "software rendering list",
   // Please update the version number whenever you change this file.
-  "version": "9.10",
+  "version": "9.11",
   "entries": [
     {
       "id": 1,
@@ -868,7 +868,11 @@
       "description": "Samsung Galaxy NOTE is too buggy to use for video decoding",
       "cr_bugs": [308721],
       "os": {
-        "type": "android"
+        "type": "android",
+        "version": {
+          "op": "<",
+          "value": "4.4"
+        }
       },
       "machine_model_name": ["GT-.*"],
       "features": [
@@ -880,7 +884,11 @@
       "description": "Samsung Galaxy S4 is too buggy to use for video decoding",
       "cr_bugs": [329072],
       "os": {
-        "type": "android"
+        "type": "android",
+        "version": {
+          "op": "<",
+          "value": "4.4"
+        }
       },
       "machine_model_name": ["SCH-.*"],
       "features": [
@@ -1117,7 +1125,11 @@
       "description": "Samsung Galaxy Tab is too buggy to use for video decoding",
       "cr_bugs": [408353],
       "os": {
-        "type": "android"
+        "type": "android",
+        "version": {
+          "op": "<",
+          "value": "4.4"
+        }
       },
       "machine_model_name": ["SM-.*"],
       "features": [
@@ -1136,6 +1148,23 @@
         "accelerated_2d_canvas",
         "gpu_rasterization"
       ]
+    },
+    {
+      "id": 103,
+      "description": "Intel GM965/GL960 crash often on Mac OS 10.6",
+      "cr_bugs": [421641],
+      "os": {
+        "type": "macosx",
+        "version": {
+          "op": "=",
+          "value": "10.6"
+        }
+      },
+      "vendor_id": "0x8086",
+      "device_id": ["0x2a02"],
+      "features": [
+        "all"
+      ]
     }
   ]
 }
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc
index a5cd9c4..afd5908 100644
--- a/gpu/gles2_conform_support/egl/display.cc
+++ b/gpu/gles2_conform_support/egl/display.cc
@@ -273,20 +273,26 @@
   return decoder_->GetCapabilities();
 }
 
-gfx::GpuMemoryBuffer* Display::CreateGpuMemoryBuffer(
-    size_t width,
-    size_t height,
-    unsigned internalformat,
-    unsigned usage,
-    int32* id) {
+int32_t Display::CreateImage(ClientBuffer buffer,
+                             size_t width,
+                             size_t height,
+                             unsigned internalformat) {
   NOTIMPLEMENTED();
-  return NULL;
+  return -1;
 }
 
-void Display::DestroyGpuMemoryBuffer(int32 id) {
+void Display::DestroyImage(int32 id) {
   NOTIMPLEMENTED();
 }
 
+int32_t Display::CreateGpuMemoryBufferImage(size_t width,
+                                            size_t height,
+                                            unsigned internalformat,
+                                            unsigned usage) {
+  NOTIMPLEMENTED();
+  return -1;
+}
+
 uint32 Display::InsertSyncPoint() {
   NOTIMPLEMENTED();
   return 0u;
diff --git a/gpu/gles2_conform_support/egl/display.h b/gpu/gles2_conform_support/egl/display.h
index 2876427..a1e82fe 100644
--- a/gpu/gles2_conform_support/egl/display.h
+++ b/gpu/gles2_conform_support/egl/display.h
@@ -75,12 +75,15 @@
 
   // GpuControl implementation.
   virtual gpu::Capabilities GetCapabilities() override;
-  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(size_t width,
-                                                      size_t height,
-                                                      unsigned internalformat,
-                                                      unsigned usage,
-                                                      int32* id) override;
-  virtual void DestroyGpuMemoryBuffer(int32 id) override;
+  virtual int32_t CreateImage(ClientBuffer buffer,
+                              size_t width,
+                              size_t height,
+                              unsigned internalformat) override;
+  virtual void DestroyImage(int32_t id) override;
+  virtual int32_t CreateGpuMemoryBufferImage(size_t width,
+                                             size_t height,
+                                             unsigned internalformat,
+                                             unsigned usage) override;
   virtual uint32 InsertSyncPoint() override;
   virtual uint32 InsertFutureSyncPoint() override;
   virtual void RetireSyncPoint(uint32 sync_point) override;
diff --git a/gpu/gpu_common.gypi b/gpu/gpu_common.gypi
index 13f3c8c..5ff16da 100644
--- a/gpu/gpu_common.gypi
+++ b/gpu/gpu_common.gypi
@@ -35,9 +35,6 @@
       'command_buffer/client/gles2_trace_implementation.cc',
       'command_buffer/client/gles2_trace_implementation.h',
       'command_buffer/client/gles2_trace_implementation_impl_autogen.h',
-      '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/gpu_switches.cc',
       'command_buffer/client/gpu_switches.h',
       'command_buffer/client/program_info_manager.cc',
diff --git a/gpu/khronos_glcts_support/khronos_glcts_test.cc b/gpu/khronos_glcts_support/khronos_glcts_test.cc
index b77bb8d..5491b15 100644
--- a/gpu/khronos_glcts_support/khronos_glcts_test.cc
+++ b/gpu/khronos_glcts_support/khronos_glcts_test.cc
@@ -9,8 +9,8 @@
 #include "base/at_exit.h"
 #include "base/base_paths.h"
 #include "base/command_line.h"
-#include "base/file_util.h"
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
diff --git a/gpu/khronos_glcts_support/khronos_glcts_test_expectations.txt b/gpu/khronos_glcts_support/khronos_glcts_test_expectations.txt
index 54c2969..8a531ac 100644
--- a/gpu/khronos_glcts_support/khronos_glcts_test_expectations.txt
+++ b/gpu/khronos_glcts_support/khronos_glcts_test_expectations.txt
@@ -24,6 +24,11 @@
 //  91531 MAC WIN LINUX : conformance_more_* = SKIP
 //  91532 MAC NVIDIA 0x0640 : tex_image_and_sub_image_2d_with_video = PASS FAIL
 
+// Chromium implements GL_ARB_texture_rectangle which makes this test fail
+139729 DEBUG RELEASE : ES2_CTS_gtf_GL_build_Texture_Rectangle_Samplers_frag = FAIL
+
+// eglGetCurrentDisplay() returns EGL_NO_DISPLAY which causes this test to fail.
+421568 DEBUG RELEASE : ES2_CTS_gtf_GL2ExtensionTests_egl_create_context_egl_create_context = FAIL
 
 ////////////////////////////////////////////////////////////////////////////////
 //
diff --git a/gpu/khronos_glcts_support/native/egl_native_windowless.cc b/gpu/khronos_glcts_support/native/egl_native_windowless.cc
index ac0e908..1a575a5 100644
--- a/gpu/khronos_glcts_support/native/egl_native_windowless.cc
+++ b/gpu/khronos_glcts_support/native/egl_native_windowless.cc
@@ -14,6 +14,29 @@
 namespace native {
 namespace windowless {
 
+class Surface : public tcu::egl::WindowSurface {
+ public:
+  Surface(tcu::egl::Display& display,
+          EGLConfig config,
+          const EGLint* attribList,
+          int width,
+          int height)
+      : tcu::egl::WindowSurface(display,
+                                config,
+                                (EGLNativeWindowType)NULL,
+                                attribList),
+        width_(width),
+        height_(height) {}
+
+  int getWidth() const { return width_; }
+
+  int getHeight() const { return height_; }
+
+ private:
+  const int width_;
+  const int height_;
+};
+
 class Window : public tcu::NativeWindow {
  public:
   Window(tcu::egl::Display& display,
@@ -23,19 +46,19 @@
          int height)
       : tcu::NativeWindow::NativeWindow(),
         eglDisplay_(display),
-        eglSurface_(display, config, (EGLNativeWindowType)NULL, attribList) {}
+        surface_(display, config, attribList, width, height) {}
 
   virtual ~Window() {}
 
   tcu::egl::Display& getEglDisplay() { return eglDisplay_; }
 
-  tcu::egl::WindowSurface& getEglSurface() { return eglSurface_; }
+  tcu::egl::WindowSurface& getEglSurface() { return surface_; }
 
   void processEvents() { return; }
 
  private:
   tcu::egl::Display& eglDisplay_;
-  tcu::egl::WindowSurface eglSurface_;
+  Surface surface_;
 };
 
 class Platform : public tcu::EglPlatform {
diff --git a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
index 0cb5758..d92f7ef 100644
--- a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
+++ b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
@@ -40,7 +40,6 @@
   functions->fCompileShader = glCompileShader;
   functions->fCompressedTexImage2D = glCompressedTexImage2D;
   functions->fCopyTexSubImage2D = glCopyTexSubImage2D;
-  functions->fCopyTextureCHROMIUM = glCopyTextureCHROMIUM;
   functions->fCreateProgram = glCreateProgram;
   functions->fCreateShader = glCreateShader;
   functions->fCullFace = glCullFace;