Add subscribeUniform extension pipeline

BUG=422978

Review URL: https://codereview.chromium.org/659903002

Cr-Commit-Position: refs/heads/master@{#303050}
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 110fb44..c1857ce 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -186,6 +186,7 @@
     "command_buffer/service/gles2_cmd_decoder_unittest_programs.cc",
     "command_buffer/service/gles2_cmd_decoder_unittest_textures.cc",
     "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc",
     "command_buffer/service/gl_surface_mock.cc",
     "command_buffer/service/gl_surface_mock.h",
     "command_buffer/service/gpu_scheduler_unittest.cc",
@@ -197,6 +198,7 @@
     "command_buffer/service/mocks.cc",
     "command_buffer/service/mocks.h",
     "command_buffer/service/program_manager_unittest.cc",
+    "command_buffer/service/valuebuffer_manager_unittest.cc",
     "command_buffer/service/query_manager_unittest.cc",
     "command_buffer/service/renderbuffer_manager_unittest.cc",
     "command_buffer/service/program_cache_unittest.cc",
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt
new file mode 100644
index 0000000..2427d32
--- /dev/null
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt
@@ -0,0 +1,113 @@
+Name
+
+    CHROMIUM_subscribe_uniform
+
+Name Strings
+
+    CHROMIUM_subscribe_uniform
+
+Version
+
+    Last Modifed Date: October 30, 2014
+
+Dependencies
+
+    OpenGL ES 2.0 is required.
+
+Overview
+
+    Allows clients to subscribe to a set of input uniforms which can
+    be populated within buffers and used to modify uniform variables within
+    their programs.
+
+    Decreases percieved latency for operations performed against these
+    uniforms.
+
+New Tokens
+
+    Accepted by the <target> parameter of glBindValueBufferCHROMIUM,
+    glSubscribeValueCHROMIUM, glPopulateSubscribedValuesCHROMIUM and
+    glUniformValueBufferCHROMIUM
+
+    GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM                        0x924B
+
+    Accepted by the <subscription> parameter of glSubscribeValueCHROMIUM and
+    glUniformValueBufferCHROMIUM:
+
+    GL_MOUSE_POSITION_CHROMIUM                                  0x924C
+
+New Procedures and Functions
+
+    The command
+
+       void glGenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers)
+
+    Generates value buffer object names.
+    <n> Specifies the number of value buffer object names to be generated.
+    <buffers> Specifies an array in which the generated value buffer object 
+              names are stored.
+
+   The command
+
+      void glDeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers)
+
+   Deletes named value buffer objects.
+   <n> Specifies the number of value buffer objects to be deleted.
+   <buffers> Specifies an array of value buffer objects to be deleted.
+
+   The command
+
+      boolean glIsValuebufferCHROMIUM(GLuint buffer);
+
+   Returns whether an object is a value buffer object.
+   <buffer> Specifies the name of a buffer object.
+
+   The command
+
+      void glBindValuebufferCHROMIUM(GLenum target, GLuint buffer);
+
+   Lets you use a named value buffer object.
+   <target> Specifies the target to which the buffer object is bound.
+   <buffer> Specifies the name of a buffer object.
+
+   The command
+
+      void glSubscribeValueCHROMIUM(GLenum target, GLenum subscription)
+
+   Subscribes the currently bound buffer object to a subscription target.
+   <target> Specifies the target to which the buffer object is bound.
+   <subscription> Specifies the subscription to which the currently bound
+                  buffer object should be subscribed.
+
+   The command
+
+      void glPopulateSubscribedValuesCHROMIUM(GLenum target)
+
+   Populates the currently bound buffer object with all subscription states
+   to which it is subscribed.
+   <target> Specifies the target to which the buffer object is bound.
+
+   The command
+ 
+      void glUniformValueBufferCHROMIUM(GLint location, GLenum target,
+                                       GLenum subscription)
+
+   Populates the uniform specified by location within the currently bound
+   program with the value in the currently bound buffer for the subscription
+   target.
+   <location> Specifies the location of the uniform variable to by modified.
+   <target> Specifies the target to which the buffer object is bound.
+   <subscription> Specifies the subscription in the currently bound buffer
+                  whose value should be used to populate the uniform.
+
+Errors
+
+    None.
+
+New State
+
+    None.
+
+Revision History
+
+    10/30/2014    Documented the extension
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index c6a3919..44587e50 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -218,6 +218,14 @@
 #define glCreateAndConsumeTextureCHROMIUM \
   GLES2_GET_FUN(CreateAndConsumeTextureCHROMIUM)
 #define glBindUniformLocationCHROMIUM GLES2_GET_FUN(BindUniformLocationCHROMIUM)
+#define glGenValuebuffersCHROMIUM GLES2_GET_FUN(GenValuebuffersCHROMIUM)
+#define glDeleteValuebuffersCHROMIUM GLES2_GET_FUN(DeleteValuebuffersCHROMIUM)
+#define glIsValuebufferCHROMIUM GLES2_GET_FUN(IsValuebufferCHROMIUM)
+#define glBindValuebufferCHROMIUM GLES2_GET_FUN(BindValuebufferCHROMIUM)
+#define glSubscribeValueCHROMIUM GLES2_GET_FUN(SubscribeValueCHROMIUM)
+#define glPopulateSubscribedValuesCHROMIUM \
+  GLES2_GET_FUN(PopulateSubscribedValuesCHROMIUM)
+#define glUniformValuebufferCHROMIUM GLES2_GET_FUN(UniformValuebufferCHROMIUM)
 #define glBindTexImage2DCHROMIUM GLES2_GET_FUN(BindTexImage2DCHROMIUM)
 #define glReleaseTexImage2DCHROMIUM GLES2_GET_FUN(ReleaseTexImage2DCHROMIUM)
 #define glTraceBeginCHROMIUM GLES2_GET_FUN(TraceBeginCHROMIUM)
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h
index b524112..200c10f 100644
--- a/gpu/GLES2/gl2extchromium.h
+++ b/gpu/GLES2/gl2extchromium.h
@@ -687,6 +687,35 @@
 #define GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM 0x924A
 #endif
 
+/* GL_CHROMIUM_subscribe_uniform */
+#ifndef GL_CHROMIUM_subscribe_uniform
+#define GL_CHROMIUM_subscribe_uniform 1
+
+#ifndef GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM
+#define GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM 0x924B
+#endif
+
+#ifndef GL_MOUSE_POSITION_CHROMIUM
+#define GL_MOUSE_POSITION_CHROMIUM 0x924C
+#endif
+
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY
+glGenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY
+glDeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers);
+GL_APICALL GLboolean GL_APIENTRY glIsValuebufferCHROMIUM(GLuint valuebuffer);
+GL_APICALL void GL_APIENTRY
+glBindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer);
+GL_APICALL void GL_APIENTRY
+glSubscribeValueCHROMIUM(GLenum target, GLenum subscription);
+GL_APICALL void GL_APIENTRY glPopulateSubscribedValuesCHROMIUM(GLenum target);
+GL_APICALL void GL_APIENTRY glUniformValuebufferCHROMIUM(GLint location,
+                                                         GLenum target,
+                                                         GLenum subscription);
+#endif
+#endif /* GL_CHROMIUM_subscribe_uniform */
+
 #ifdef GL_GLEXT_PROTOTYPES
 GL_APICALL void GL_APIENTRY
     glScheduleOverlayPlaneCHROMIUM(GLint plane_z_order,
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 94c3b34..8d7332f 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1195,6 +1195,18 @@
       'GL_SCANOUT_CHROMIUM'
     ],
   },
+  'ValueBufferTarget': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM',
+    ],
+  },
+  'SubscriptionTarget': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_MOUSE_POSITION_CHROMIUM',
+    ],
+  },
   'VertexAttribType': {
     'type': 'GLenum',
     'valid': [
@@ -1448,6 +1460,57 @@
     'extension': "CHROMIUM_texture_mailbox",
     'chromium': True,
   },
+  'GenValuebuffersCHROMIUM': {
+    'type': 'GENn',
+    'gl_test_func': 'glGenValuebuffersCHROMIUM',
+    'resource_type': 'Valuebuffer',
+    'resource_types': 'Valuebuffers',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'DeleteValuebuffersCHROMIUM': {
+    'type': 'DELn',
+    'gl_test_func': 'glDeleteValuebuffersCHROMIUM',
+    'resource_type': 'Valuebuffer',
+    'resource_types': 'Valuebuffers',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'IsValuebufferCHROMIUM': {
+    'type': 'Is',
+    'decoder_func': 'DoIsValuebufferCHROMIUM',
+    'expectation': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'BindValuebufferCHROMIUM': {
+    'type': 'Bind',
+    'decoder_func': 'DoBindValueBufferCHROMIUM',
+    'gen_func': 'GenValueBuffersCHROMIUM',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'SubscribeValueCHROMIUM': {
+    'decoder_func': 'DoSubscribeValueCHROMIUM',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'PopulateSubscribedValuesCHROMIUM': {
+    'decoder_func': 'DoPopulateSubscribedValuesCHROMIUM',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'UniformValuebufferCHROMIUM': {
+    'decoder_func': 'DoUniformValueBufferCHROMIUM',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
   'ClearStencil': {
     'type': 'StateSet',
     'state': 'ClearStencil',
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 392bb22f..6f019e3c 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -860,6 +860,30 @@
                                       const char* name) {
   gles2::GetGLContext()->BindUniformLocationCHROMIUM(program, location, name);
 }
+void GLES2GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) {
+  gles2::GetGLContext()->GenValuebuffersCHROMIUM(n, buffers);
+}
+void GLES2DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) {
+  gles2::GetGLContext()->DeleteValuebuffersCHROMIUM(n, valuebuffers);
+}
+GLboolean GLES2IsValuebufferCHROMIUM(GLuint valuebuffer) {
+  return gles2::GetGLContext()->IsValuebufferCHROMIUM(valuebuffer);
+}
+void GLES2BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) {
+  gles2::GetGLContext()->BindValuebufferCHROMIUM(target, valuebuffer);
+}
+void GLES2SubscribeValueCHROMIUM(GLenum target, GLenum subscription) {
+  gles2::GetGLContext()->SubscribeValueCHROMIUM(target, subscription);
+}
+void GLES2PopulateSubscribedValuesCHROMIUM(GLenum target) {
+  gles2::GetGLContext()->PopulateSubscribedValuesCHROMIUM(target);
+}
+void GLES2UniformValuebufferCHROMIUM(GLint location,
+                                     GLenum target,
+                                     GLenum subscription) {
+  gles2::GetGLContext()->UniformValuebufferCHROMIUM(location, target,
+                                                    subscription);
+}
 void GLES2BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
   gles2::GetGLContext()->BindTexImage2DCHROMIUM(target, imageId);
 }
@@ -1752,6 +1776,34 @@
      reinterpret_cast<GLES2FunctionPointer>(glBindUniformLocationCHROMIUM),
     },
     {
+     "glGenValuebuffersCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glGenValuebuffersCHROMIUM),
+    },
+    {
+     "glDeleteValuebuffersCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glDeleteValuebuffersCHROMIUM),
+    },
+    {
+     "glIsValuebufferCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glIsValuebufferCHROMIUM),
+    },
+    {
+     "glBindValuebufferCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glBindValuebufferCHROMIUM),
+    },
+    {
+     "glSubscribeValueCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glSubscribeValueCHROMIUM),
+    },
+    {
+     "glPopulateSubscribedValuesCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glPopulateSubscribedValuesCHROMIUM),
+    },
+    {
+     "glUniformValuebufferCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glUniformValuebufferCHROMIUM),
+    },
+    {
      "glBindTexImage2DCHROMIUM",
      reinterpret_cast<GLES2FunctionPointer>(glBindTexImage2DCHROMIUM),
     },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 24d8be2..8477043 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -1725,6 +1725,73 @@
   }
 }
 
+void GenValuebuffersCHROMIUMImmediate(GLsizei n, GLuint* buffers) {
+  const uint32_t size =
+      gles2::cmds::GenValuebuffersCHROMIUMImmediate::ComputeSize(n);
+  gles2::cmds::GenValuebuffersCHROMIUMImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::GenValuebuffersCHROMIUMImmediate>(size);
+  if (c) {
+    c->Init(n, buffers);
+  }
+}
+
+void DeleteValuebuffersCHROMIUMImmediate(GLsizei n,
+                                         const GLuint* valuebuffers) {
+  const uint32_t size =
+      gles2::cmds::DeleteValuebuffersCHROMIUMImmediate::ComputeSize(n);
+  gles2::cmds::DeleteValuebuffersCHROMIUMImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::DeleteValuebuffersCHROMIUMImmediate>(size);
+  if (c) {
+    c->Init(n, valuebuffers);
+  }
+}
+
+void IsValuebufferCHROMIUM(GLuint valuebuffer,
+                           uint32_t result_shm_id,
+                           uint32_t result_shm_offset) {
+  gles2::cmds::IsValuebufferCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::IsValuebufferCHROMIUM>();
+  if (c) {
+    c->Init(valuebuffer, result_shm_id, result_shm_offset);
+  }
+}
+
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) {
+  gles2::cmds::BindValuebufferCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::BindValuebufferCHROMIUM>();
+  if (c) {
+    c->Init(target, valuebuffer);
+  }
+}
+
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) {
+  gles2::cmds::SubscribeValueCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::SubscribeValueCHROMIUM>();
+  if (c) {
+    c->Init(target, subscription);
+  }
+}
+
+void PopulateSubscribedValuesCHROMIUM(GLenum target) {
+  gles2::cmds::PopulateSubscribedValuesCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::PopulateSubscribedValuesCHROMIUM>();
+  if (c) {
+    c->Init(target);
+  }
+}
+
+void UniformValuebufferCHROMIUM(GLint location,
+                                GLenum target,
+                                GLenum subscription) {
+  gles2::cmds::UniformValuebufferCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::UniformValuebufferCHROMIUM>();
+  if (c) {
+    c->Init(location, target, subscription);
+  }
+}
+
 void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
   gles2::cmds::BindTexImage2DCHROMIUM* c =
       GetCmdSpace<gles2::cmds::BindTexImage2DCHROMIUM>();
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 66d8c2bb..4f5254b 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -2364,6 +2364,11 @@
     GLsizei /* n */, const GLuint* /* queries */) {
 }
 
+void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
+    GLsizei /* n */,
+    const GLuint* /* valuebuffers */) {
+}
+
 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
 // generates a new resource. On newer versions of OpenGL they don't. The code
 // related to binding below will need to change if we switch to the new OpenGL
@@ -2513,6 +2518,26 @@
   return changed;
 }
 
+bool GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
+                                                        GLuint valuebuffer) {
+  bool changed = false;
+  switch (target) {
+    case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
+      if (bound_valuebuffer_ != valuebuffer) {
+        bound_valuebuffer_ = valuebuffer;
+        changed = true;
+      }
+      break;
+    default:
+      changed = true;
+      break;
+  }
+  // TODO(gman): There's a bug here. If the target is invalid the ID will not be
+  // used even though it's marked it as used here.
+  GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(valuebuffer);
+  return changed;
+}
+
 bool GLES2Implementation::UseProgramHelper(GLuint program) {
   bool changed = false;
   if (current_program_ != program) {
@@ -2629,6 +2654,11 @@
   }
 }
 
+void GLES2Implementation::DeleteTexturesStub(GLsizei n,
+                                             const GLuint* textures) {
+  helper_->DeleteTexturesImmediate(n, textures);
+}
+
 void GLES2Implementation::DeleteVertexArraysOESHelper(
     GLsizei n, const GLuint* arrays) {
   vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
@@ -2646,9 +2676,27 @@
   helper_->DeleteVertexArraysOESImmediate(n, arrays);
 }
 
-void GLES2Implementation::DeleteTexturesStub(
-    GLsizei n, const GLuint* textures) {
-  helper_->DeleteTexturesImmediate(n, textures);
+void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
+    GLsizei n,
+    const GLuint* valuebuffers) {
+  if (!GetIdHandler(id_namespaces::kValuebuffers)
+           ->FreeIds(this, n, valuebuffers,
+                     &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
+    SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
+               "id not created by this context.");
+    return;
+  }
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    if (valuebuffers[ii] == bound_valuebuffer_) {
+      bound_valuebuffer_ = 0;
+    }
+  }
+}
+
+void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
+    GLsizei n,
+    const GLuint* valuebuffers) {
+  helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
 }
 
 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index a612ac2..c2e9edb 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -495,17 +495,19 @@
 
   // Returns true if id is reserved.
   bool IsBufferReservedId(GLuint id);
-  bool IsFramebufferReservedId(GLuint id) { return false;  }
+  bool IsFramebufferReservedId(GLuint id) { return false; }
   bool IsRenderbufferReservedId(GLuint id) { return false; }
   bool IsTextureReservedId(GLuint id) { return false; }
   bool IsVertexArrayReservedId(GLuint id) { return false; }
   bool IsProgramReservedId(GLuint id) { return false; }
+  bool IsValuebufferReservedId(GLuint id) { return false; }
 
   bool BindBufferHelper(GLenum target, GLuint texture);
   bool BindFramebufferHelper(GLenum target, GLuint texture);
   bool BindRenderbufferHelper(GLenum target, GLuint texture);
   bool BindTextureHelper(GLenum target, GLuint texture);
   bool BindVertexArrayOESHelper(GLuint array);
+  bool BindValuebufferCHROMIUMHelper(GLenum target, GLuint valuebuffer);
   bool UseProgramHelper(GLuint program);
 
   void GenBuffersHelper(GLsizei n, const GLuint* buffers);
@@ -514,6 +516,7 @@
   void GenTexturesHelper(GLsizei n, const GLuint* textures);
   void GenVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
   void GenQueriesEXTHelper(GLsizei n, const GLuint* queries);
+  void GenValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* valuebuffers);
 
   void DeleteBuffersHelper(GLsizei n, const GLuint* buffers);
   void DeleteFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
@@ -523,6 +526,7 @@
   bool DeleteShaderHelper(GLuint shader);
   void DeleteQueriesEXTHelper(GLsizei n, const GLuint* queries);
   void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
+  void DeleteValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* valuebuffers);
 
   void DeleteBuffersStub(GLsizei n, const GLuint* buffers);
   void DeleteFramebuffersStub(GLsizei n, const GLuint* framebuffers);
@@ -531,6 +535,7 @@
   void DeleteProgramStub(GLsizei n, const GLuint* programs);
   void DeleteShaderStub(GLsizei n, const GLuint* shaders);
   void DeleteVertexArraysOESStub(GLsizei n, const GLuint* arrays);
+  void DeleteValuebuffersCHROMIUMStub(GLsizei n, const GLuint* valuebuffers);
 
   void BufferDataHelper(
       GLenum target, GLsizeiptr size, const void* data, GLenum usage);
@@ -699,6 +704,7 @@
   GLuint bound_framebuffer_;
   GLuint bound_read_framebuffer_;
   GLuint bound_renderbuffer_;
+  GLuint bound_valuebuffer_;
 
   // The program in use by glUseProgram
   GLuint current_program_;
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 4e547d9..3a11f105 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -629,6 +629,22 @@
                                  GLint location,
                                  const char* name) override;
 
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+
+void UniformValuebufferCHROMIUM(GLint location,
+                                GLenum target,
+                                GLenum subscription) override;
+
 void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 
 void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 32b13476..ab2adee0 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -2024,6 +2024,120 @@
   CheckGLError();
 }
 
+void GLES2Implementation::GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) {
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenValuebuffersCHROMIUM(" << n
+                     << ", " << static_cast<const void*>(buffers) << ")");
+  if (n < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGenValuebuffersCHROMIUM", "n < 0");
+    return;
+  }
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GetIdHandler(id_namespaces::kValuebuffers)->MakeIds(this, 0, n, buffers);
+  GenValuebuffersCHROMIUMHelper(n, buffers);
+  helper_->GenValuebuffersCHROMIUMImmediate(n, buffers);
+  if (share_group_->bind_generates_resource())
+    helper_->CommandBufferHelper::Flush();
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << buffers[i]);
+    }
+  });
+  CheckGLError();
+}
+
+void GLES2Implementation::DeleteValuebuffersCHROMIUM(
+    GLsizei n,
+    const GLuint* valuebuffers) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteValuebuffersCHROMIUM(" << n
+                     << ", " << static_cast<const void*>(valuebuffers) << ")");
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << valuebuffers[i]);
+    }
+  });
+  GPU_CLIENT_DCHECK_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      DCHECK(valuebuffers[i] != 0);
+    }
+  });
+  if (n < 0) {
+    SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM", "n < 0");
+    return;
+  }
+  DeleteValuebuffersCHROMIUMHelper(n, valuebuffers);
+  CheckGLError();
+}
+
+GLboolean GLES2Implementation::IsValuebufferCHROMIUM(GLuint valuebuffer) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  TRACE_EVENT0("gpu", "GLES2Implementation::IsValuebufferCHROMIUM");
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsValuebufferCHROMIUM("
+                     << valuebuffer << ")");
+  typedef cmds::IsValuebufferCHROMIUM::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return GL_FALSE;
+  }
+  *result = 0;
+  helper_->IsValuebufferCHROMIUM(valuebuffer, GetResultShmId(),
+                                 GetResultShmOffset());
+  WaitForCmd();
+  GLboolean result_value = *result != 0;
+  GPU_CLIENT_LOG("returned " << result_value);
+  CheckGLError();
+  return result_value;
+}
+
+void GLES2Implementation::BindValuebufferCHROMIUM(GLenum target,
+                                                  GLuint valuebuffer) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindValuebufferCHROMIUM("
+                     << GLES2Util::GetStringValueBufferTarget(target) << ", "
+                     << valuebuffer << ")");
+  if (IsValuebufferReservedId(valuebuffer)) {
+    SetGLError(GL_INVALID_OPERATION, "BindValuebufferCHROMIUM",
+               "valuebuffer reserved id");
+    return;
+  }
+  if (BindValuebufferCHROMIUMHelper(target, valuebuffer)) {
+    helper_->BindValuebufferCHROMIUM(target, valuebuffer);
+  }
+  CheckGLError();
+}
+
+void GLES2Implementation::SubscribeValueCHROMIUM(GLenum target,
+                                                 GLenum subscription) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSubscribeValueCHROMIUM("
+                     << GLES2Util::GetStringValueBufferTarget(target) << ", "
+                     << GLES2Util::GetStringSubscriptionTarget(subscription)
+                     << ")");
+  helper_->SubscribeValueCHROMIUM(target, subscription);
+  CheckGLError();
+}
+
+void GLES2Implementation::PopulateSubscribedValuesCHROMIUM(GLenum target) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix()
+                     << "] glPopulateSubscribedValuesCHROMIUM("
+                     << GLES2Util::GetStringValueBufferTarget(target) << ")");
+  helper_->PopulateSubscribedValuesCHROMIUM(target);
+  CheckGLError();
+}
+
+void GLES2Implementation::UniformValuebufferCHROMIUM(GLint location,
+                                                     GLenum target,
+                                                     GLenum subscription) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG(
+      "[" << GetLogPrefix() << "] glUniformValuebufferCHROMIUM(" << location
+          << ", " << GLES2Util::GetStringValueBufferTarget(target) << ", "
+          << GLES2Util::GetStringSubscriptionTarget(subscription) << ")");
+  helper_->UniformValuebufferCHROMIUM(location, target, subscription);
+  CheckGLError();
+}
+
 void GLES2Implementation::BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindTexImage2DCHROMIUM("
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 3d2f089..72ffc30 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -383,6 +383,7 @@
   static const GLuint kTexturesStartId = 1;
   static const GLuint kQueriesStartId = 1;
   static const GLuint kVertexArraysStartId = 1;
+  static const GLuint kValuebuffersStartId = 1;
 
   typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo;
 
@@ -755,6 +756,7 @@
 const GLuint GLES2ImplementationTest::kTexturesStartId;
 const GLuint GLES2ImplementationTest::kQueriesStartId;
 const GLuint GLES2ImplementationTest::kVertexArraysStartId;
+const GLuint GLES2ImplementationTest::kValuebuffersStartId;
 #endif
 
 TEST_F(GLES2ImplementationTest, Basic) {
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index a42d6d5d..240f554 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -1804,6 +1804,108 @@
 // TODO: Implement unit test for GenMailboxCHROMIUM
 // TODO: Implement unit test for BindUniformLocationCHROMIUM
 
+TEST_F(GLES2ImplementationTest, GenValuebuffersCHROMIUM) {
+  GLuint ids[2] = {
+      0,
+  };
+  struct Cmds {
+    cmds::GenValuebuffersCHROMIUMImmediate gen;
+    GLuint data[2];
+  };
+  Cmds expected;
+  expected.gen.Init(arraysize(ids), &ids[0]);
+  expected.data[0] = kValuebuffersStartId;
+  expected.data[1] = kValuebuffersStartId + 1;
+  gl_->GenValuebuffersCHROMIUM(arraysize(ids), &ids[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_EQ(kValuebuffersStartId, ids[0]);
+  EXPECT_EQ(kValuebuffersStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, DeleteValuebuffersCHROMIUM) {
+  GLuint ids[2] = {kValuebuffersStartId, kValuebuffersStartId + 1};
+  struct Cmds {
+    cmds::DeleteValuebuffersCHROMIUMImmediate del;
+    GLuint data[2];
+  };
+  Cmds expected;
+  expected.del.Init(arraysize(ids), &ids[0]);
+  expected.data[0] = kValuebuffersStartId;
+  expected.data[1] = kValuebuffersStartId + 1;
+  gl_->DeleteValuebuffersCHROMIUM(arraysize(ids), &ids[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, IsValuebufferCHROMIUM) {
+  struct Cmds {
+    cmds::IsValuebufferCHROMIUM cmd;
+  };
+
+  Cmds expected;
+  ExpectedMemoryInfo result1 =
+      GetExpectedResultMemory(sizeof(cmds::IsValuebufferCHROMIUM::Result));
+  expected.cmd.Init(1, result1.id, result1.offset);
+
+  EXPECT_CALL(*command_buffer(), OnFlush())
+      .WillOnce(SetMemory(result1.ptr, uint32_t(1)))
+      .RetiresOnSaturation();
+
+  GLboolean result = gl_->IsValuebufferCHROMIUM(1);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, BindValuebufferCHROMIUM) {
+  struct Cmds {
+    cmds::BindValuebufferCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+
+  gl_->BindValuebufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  ClearCommands();
+  gl_->BindValuebufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+  EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationTest, SubscribeValueCHROMIUM) {
+  struct Cmds {
+    cmds::SubscribeValueCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+                    GL_MOUSE_POSITION_CHROMIUM);
+
+  gl_->SubscribeValueCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+                              GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, PopulateSubscribedValuesCHROMIUM) {
+  struct Cmds {
+    cmds::PopulateSubscribedValuesCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+
+  gl_->PopulateSubscribedValuesCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, UniformValuebufferCHROMIUM) {
+  struct Cmds {
+    cmds::UniformValuebufferCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(1, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+                    GL_MOUSE_POSITION_CHROMIUM);
+
+  gl_->UniformValuebufferCHROMIUM(1, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+                                  GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, BindTexImage2DCHROMIUM) {
   struct Cmds {
     cmds::BindTexImage2DCHROMIUM cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index d840804..af5db19 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -450,6 +450,16 @@
 virtual void BindUniformLocationCHROMIUM(GLuint program,
                                          GLint location,
                                          const char* name) = 0;
+virtual void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) = 0;
+virtual void DeleteValuebuffersCHROMIUM(GLsizei n,
+                                        const GLuint* valuebuffers) = 0;
+virtual GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) = 0;
+virtual void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) = 0;
+virtual void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) = 0;
+virtual void PopulateSubscribedValuesCHROMIUM(GLenum target) = 0;
+virtual void UniformValuebufferCHROMIUM(GLint location,
+                                        GLenum target,
+                                        GLenum subscription) = 0;
 virtual void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) = 0;
 virtual void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) = 0;
 virtual void TraceBeginCHROMIUM(const char* name) = 0;
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 687ff48..c540360 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -441,6 +441,15 @@
 void BindUniformLocationCHROMIUM(GLuint program,
                                  GLint location,
                                  const char* name) override;
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+void UniformValuebufferCHROMIUM(GLint location,
+                                GLenum target,
+                                GLenum subscription) override;
 void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 void TraceBeginCHROMIUM(const char* name) override;
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 e78b07c..78fe6d3 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -781,6 +781,28 @@
                                                      GLint /* location */,
                                                      const char* /* name */) {
 }
+void GLES2InterfaceStub::GenValuebuffersCHROMIUM(GLsizei /* n */,
+                                                 GLuint* /* buffers */) {
+}
+void GLES2InterfaceStub::DeleteValuebuffersCHROMIUM(
+    GLsizei /* n */,
+    const GLuint* /* valuebuffers */) {
+}
+GLboolean GLES2InterfaceStub::IsValuebufferCHROMIUM(GLuint /* valuebuffer */) {
+  return 0;
+}
+void GLES2InterfaceStub::BindValuebufferCHROMIUM(GLenum /* target */,
+                                                 GLuint /* valuebuffer */) {
+}
+void GLES2InterfaceStub::SubscribeValueCHROMIUM(GLenum /* target */,
+                                                GLenum /* subscription */) {
+}
+void GLES2InterfaceStub::PopulateSubscribedValuesCHROMIUM(GLenum /* target */) {
+}
+void GLES2InterfaceStub::UniformValuebufferCHROMIUM(GLint /* location */,
+                                                    GLenum /* target */,
+                                                    GLenum /* subscription */) {
+}
 void GLES2InterfaceStub::BindTexImage2DCHROMIUM(GLenum /* target */,
                                                 GLint /* imageId */) {
 }
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index a599eb4..cb609108 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -441,6 +441,15 @@
 void BindUniformLocationCHROMIUM(GLuint program,
                                  GLint location,
                                  const char* name) override;
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+void UniformValuebufferCHROMIUM(GLint location,
+                                GLenum target,
+                                GLenum subscription) override;
 void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 void TraceBeginCHROMIUM(const char* name) override;
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 3173a25..2fe7de1 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1365,6 +1365,51 @@
   gl_->BindUniformLocationCHROMIUM(program, location, name);
 }
 
+void GLES2TraceImplementation::GenValuebuffersCHROMIUM(GLsizei n,
+                                                       GLuint* buffers) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenValuebuffersCHROMIUM");
+  gl_->GenValuebuffersCHROMIUM(n, buffers);
+}
+
+void GLES2TraceImplementation::DeleteValuebuffersCHROMIUM(
+    GLsizei n,
+    const GLuint* valuebuffers) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "GLES2Trace::DeleteValuebuffersCHROMIUM");
+  gl_->DeleteValuebuffersCHROMIUM(n, valuebuffers);
+}
+
+GLboolean GLES2TraceImplementation::IsValuebufferCHROMIUM(GLuint valuebuffer) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsValuebufferCHROMIUM");
+  return gl_->IsValuebufferCHROMIUM(valuebuffer);
+}
+
+void GLES2TraceImplementation::BindValuebufferCHROMIUM(GLenum target,
+                                                       GLuint valuebuffer) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindValuebufferCHROMIUM");
+  gl_->BindValuebufferCHROMIUM(target, valuebuffer);
+}
+
+void GLES2TraceImplementation::SubscribeValueCHROMIUM(GLenum target,
+                                                      GLenum subscription) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SubscribeValueCHROMIUM");
+  gl_->SubscribeValueCHROMIUM(target, subscription);
+}
+
+void GLES2TraceImplementation::PopulateSubscribedValuesCHROMIUM(GLenum target) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "GLES2Trace::PopulateSubscribedValuesCHROMIUM");
+  gl_->PopulateSubscribedValuesCHROMIUM(target);
+}
+
+void GLES2TraceImplementation::UniformValuebufferCHROMIUM(GLint location,
+                                                          GLenum target,
+                                                          GLenum subscription) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "GLES2Trace::UniformValuebufferCHROMIUM");
+  gl_->UniformValuebufferCHROMIUM(location, target, subscription);
+}
+
 void GLES2TraceImplementation::BindTexImage2DCHROMIUM(GLenum target,
                                                       GLint imageId) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindTexImage2DCHROMIUM");
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 37c33be0..92053e0 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -202,6 +202,13 @@
 GL_APICALL void         GL_APIENTRY glConsumeTextureCHROMIUM (GLenumTextureBindTarget target, const GLbyte* mailbox);
 GL_APICALL GLuint       GL_APIENTRY glCreateAndConsumeTextureCHROMIUM (GLenumTextureBindTarget target, const GLbyte* mailbox);
 GL_APICALL void         GL_APIENTRY glBindUniformLocationCHROMIUM (GLidProgram program, GLint location, const char* name);
+GL_APICALL void         GL_APIENTRY glGenValuebuffersCHROMIUM (GLsizeiNotNegative n, GLuint* buffers);
+GL_APICALL void         GL_APIENTRY glDeleteValuebuffersCHROMIUM (GLsizeiNotNegative n, const GLuint* valuebuffers);
+GL_APICALL GLboolean    GL_APIENTRY glIsValuebufferCHROMIUM (GLidBindValuebuffer valuebuffer);
+GL_APICALL void         GL_APIENTRY glBindValuebufferCHROMIUM (GLenumValueBufferTarget target, GLidBindValuebuffer valuebuffer);
+GL_APICALL void         GL_APIENTRY glSubscribeValueCHROMIUM (GLenumValueBufferTarget target, GLenumSubscriptionTarget subscription);
+GL_APICALL void         GL_APIENTRY glPopulateSubscribedValuesCHROMIUM (GLenumValueBufferTarget target);
+GL_APICALL void         GL_APIENTRY glUniformValuebufferCHROMIUM (GLintUniformLocation location, GLenumValueBufferTarget target, GLenumSubscriptionTarget subscription);
 GL_APICALL void         GL_APIENTRY glBindTexImage2DCHROMIUM (GLenumTextureBindTarget target, GLint imageId);
 GL_APICALL void         GL_APIENTRY glReleaseTexImage2DCHROMIUM (GLenumTextureBindTarget target, GLint imageId);
 GL_APICALL void         GL_APIENTRY glTraceBeginCHROMIUM (const char* name);
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index 393303e..c0bc663 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -59,6 +59,7 @@
   kTextures,
   kQueries,
   kVertexArrays,
+  kValuebuffers,
   kNumIdNamespaces
 };
 
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index 487e8b7..9304ec9 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -8226,6 +8226,287 @@
     offsetof(BindUniformLocationCHROMIUMBucket, name_bucket_id) == 12,
     OffsetOf_BindUniformLocationCHROMIUMBucket_name_bucket_id_not_12);
 
+struct GenValuebuffersCHROMIUMImmediate {
+  typedef GenValuebuffersCHROMIUMImmediate ValueType;
+  static const CommandId kCmdId = kGenValuebuffersCHROMIUMImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei n) {
+    return static_cast<uint32_t>(sizeof(GLuint) * n);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei n) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(n));  // NOLINT
+  }
+
+  void SetHeader(GLsizei n) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+  }
+
+  void Init(GLsizei _n, GLuint* _buffers) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _buffers, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, GLuint* _buffers) {
+    static_cast<ValueType*>(cmd)->Init(_n, _buffers);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(GenValuebuffersCHROMIUMImmediate) == 8,
+               Sizeof_GenValuebuffersCHROMIUMImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenValuebuffersCHROMIUMImmediate, header) == 0,
+               OffsetOf_GenValuebuffersCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenValuebuffersCHROMIUMImmediate, n) == 4,
+               OffsetOf_GenValuebuffersCHROMIUMImmediate_n_not_4);
+
+struct DeleteValuebuffersCHROMIUMImmediate {
+  typedef DeleteValuebuffersCHROMIUMImmediate ValueType;
+  static const CommandId kCmdId = kDeleteValuebuffersCHROMIUMImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei n) {
+    return static_cast<uint32_t>(sizeof(GLuint) * n);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei n) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(n));  // NOLINT
+  }
+
+  void SetHeader(GLsizei n) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+  }
+
+  void Init(GLsizei _n, const GLuint* _valuebuffers) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _valuebuffers, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, const GLuint* _valuebuffers) {
+    static_cast<ValueType*>(cmd)->Init(_n, _valuebuffers);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteValuebuffersCHROMIUMImmediate) == 8,
+               Sizeof_DeleteValuebuffersCHROMIUMImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteValuebuffersCHROMIUMImmediate, header) == 0,
+               OffsetOf_DeleteValuebuffersCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteValuebuffersCHROMIUMImmediate, n) == 4,
+               OffsetOf_DeleteValuebuffersCHROMIUMImmediate_n_not_4);
+
+struct IsValuebufferCHROMIUM {
+  typedef IsValuebufferCHROMIUM ValueType;
+  static const CommandId kCmdId = kIsValuebufferCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef uint32_t Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _valuebuffer,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    SetHeader();
+    valuebuffer = _valuebuffer;
+    result_shm_id = _result_shm_id;
+    result_shm_offset = _result_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _valuebuffer,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_valuebuffer, _result_shm_id, _result_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t valuebuffer;
+  uint32_t result_shm_id;
+  uint32_t result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsValuebufferCHROMIUM) == 16,
+               Sizeof_IsValuebufferCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, header) == 0,
+               OffsetOf_IsValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, valuebuffer) == 4,
+               OffsetOf_IsValuebufferCHROMIUM_valuebuffer_not_4);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, result_shm_id) == 8,
+               OffsetOf_IsValuebufferCHROMIUM_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, result_shm_offset) == 12,
+               OffsetOf_IsValuebufferCHROMIUM_result_shm_offset_not_12);
+
+struct BindValuebufferCHROMIUM {
+  typedef BindValuebufferCHROMIUM ValueType;
+  static const CommandId kCmdId = kBindValuebufferCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target, GLuint _valuebuffer) {
+    SetHeader();
+    target = _target;
+    valuebuffer = _valuebuffer;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLuint _valuebuffer) {
+    static_cast<ValueType*>(cmd)->Init(_target, _valuebuffer);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t valuebuffer;
+};
+
+COMPILE_ASSERT(sizeof(BindValuebufferCHROMIUM) == 12,
+               Sizeof_BindValuebufferCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, header) == 0,
+               OffsetOf_BindValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, target) == 4,
+               OffsetOf_BindValuebufferCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, valuebuffer) == 8,
+               OffsetOf_BindValuebufferCHROMIUM_valuebuffer_not_8);
+
+struct SubscribeValueCHROMIUM {
+  typedef SubscribeValueCHROMIUM ValueType;
+  static const CommandId kCmdId = kSubscribeValueCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target, GLenum _subscription) {
+    SetHeader();
+    target = _target;
+    subscription = _subscription;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLenum _subscription) {
+    static_cast<ValueType*>(cmd)->Init(_target, _subscription);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t subscription;
+};
+
+COMPILE_ASSERT(sizeof(SubscribeValueCHROMIUM) == 12,
+               Sizeof_SubscribeValueCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, header) == 0,
+               OffsetOf_SubscribeValueCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, target) == 4,
+               OffsetOf_SubscribeValueCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, subscription) == 8,
+               OffsetOf_SubscribeValueCHROMIUM_subscription_not_8);
+
+struct PopulateSubscribedValuesCHROMIUM {
+  typedef PopulateSubscribedValuesCHROMIUM ValueType;
+  static const CommandId kCmdId = kPopulateSubscribedValuesCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLenum _target) {
+    SetHeader();
+    target = _target;
+  }
+
+  void* Set(void* cmd, GLenum _target) {
+    static_cast<ValueType*>(cmd)->Init(_target);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+};
+
+COMPILE_ASSERT(sizeof(PopulateSubscribedValuesCHROMIUM) == 8,
+               Sizeof_PopulateSubscribedValuesCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(PopulateSubscribedValuesCHROMIUM, header) == 0,
+               OffsetOf_PopulateSubscribedValuesCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(PopulateSubscribedValuesCHROMIUM, target) == 4,
+               OffsetOf_PopulateSubscribedValuesCHROMIUM_target_not_4);
+
+struct UniformValuebufferCHROMIUM {
+  typedef UniformValuebufferCHROMIUM ValueType;
+  static const CommandId kCmdId = kUniformValuebufferCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLint _location, GLenum _target, GLenum _subscription) {
+    SetHeader();
+    location = _location;
+    target = _target;
+    subscription = _subscription;
+  }
+
+  void* Set(void* cmd, GLint _location, GLenum _target, GLenum _subscription) {
+    static_cast<ValueType*>(cmd)->Init(_location, _target, _subscription);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  int32_t location;
+  uint32_t target;
+  uint32_t subscription;
+};
+
+COMPILE_ASSERT(sizeof(UniformValuebufferCHROMIUM) == 16,
+               Sizeof_UniformValuebufferCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, header) == 0,
+               OffsetOf_UniformValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, location) == 4,
+               OffsetOf_UniformValuebufferCHROMIUM_location_not_4);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, target) == 8,
+               OffsetOf_UniformValuebufferCHROMIUM_target_not_8);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, subscription) == 12,
+               OffsetOf_UniformValuebufferCHROMIUM_subscription_not_12);
+
 struct BindTexImage2DCHROMIUM {
   typedef BindTexImage2DCHROMIUM ValueType;
   static const CommandId kCmdId = kBindTexImage2DCHROMIUM;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index b26afb1..9e91d00 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -3143,6 +3143,111 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, GenValuebuffersCHROMIUMImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::GenValuebuffersCHROMIUMImmediate& cmd =
+      *GetBufferAs<cmds::GenValuebuffersCHROMIUMImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::GenValuebuffersCHROMIUMImmediate::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd,
+      sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+  // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DeleteValuebuffersCHROMIUMImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::DeleteValuebuffersCHROMIUMImmediate& cmd =
+      *GetBufferAs<cmds::DeleteValuebuffersCHROMIUMImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::DeleteValuebuffersCHROMIUMImmediate::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd,
+      sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+  // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, IsValuebufferCHROMIUM) {
+  cmds::IsValuebufferCHROMIUM& cmd =
+      *GetBufferAs<cmds::IsValuebufferCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12),
+              static_cast<uint32_t>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::IsValuebufferCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.valuebuffer);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.result_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.result_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindValuebufferCHROMIUM) {
+  cmds::BindValuebufferCHROMIUM& cmd =
+      *GetBufferAs<cmds::BindValuebufferCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BindValuebufferCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.valuebuffer);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, SubscribeValueCHROMIUM) {
+  cmds::SubscribeValueCHROMIUM& cmd =
+      *GetBufferAs<cmds::SubscribeValueCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLenum>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::SubscribeValueCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.subscription);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, PopulateSubscribedValuesCHROMIUM) {
+  cmds::PopulateSubscribedValuesCHROMIUM& cmd =
+      *GetBufferAs<cmds::PopulateSubscribedValuesCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::PopulateSubscribedValuesCHROMIUM::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, UniformValuebufferCHROMIUM) {
+  cmds::UniformValuebufferCHROMIUM& cmd =
+      *GetBufferAs<cmds::UniformValuebufferCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLint>(11),
+                           static_cast<GLenum>(12), static_cast<GLenum>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::UniformValuebufferCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.target);
+  EXPECT_EQ(static_cast<GLenum>(13), cmd.subscription);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, BindTexImage2DCHROMIUM) {
   cmds::BindTexImage2DCHROMIUM& cmd =
       *GetBufferAs<cmds::BindTexImage2DCHROMIUM>();
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 8bd5c0a..a34e7d2 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -193,24 +193,31 @@
   OP(ConsumeTextureCHROMIUMImmediate)          /* 434 */ \
   OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 435 */ \
   OP(BindUniformLocationCHROMIUMBucket)        /* 436 */ \
-  OP(BindTexImage2DCHROMIUM)                   /* 437 */ \
-  OP(ReleaseTexImage2DCHROMIUM)                /* 438 */ \
-  OP(TraceBeginCHROMIUM)                       /* 439 */ \
-  OP(TraceEndCHROMIUM)                         /* 440 */ \
-  OP(AsyncTexSubImage2DCHROMIUM)               /* 441 */ \
-  OP(AsyncTexImage2DCHROMIUM)                  /* 442 */ \
-  OP(WaitAsyncTexImage2DCHROMIUM)              /* 443 */ \
-  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 444 */ \
-  OP(DiscardFramebufferEXTImmediate)           /* 445 */ \
-  OP(LoseContextCHROMIUM)                      /* 446 */ \
-  OP(InsertSyncPointCHROMIUM)                  /* 447 */ \
-  OP(WaitSyncPointCHROMIUM)                    /* 448 */ \
-  OP(DrawBuffersEXTImmediate)                  /* 449 */ \
-  OP(DiscardBackbufferCHROMIUM)                /* 450 */ \
-  OP(ScheduleOverlayPlaneCHROMIUM)             /* 451 */ \
-  OP(MatrixLoadfCHROMIUMImmediate)             /* 452 */ \
-  OP(MatrixLoadIdentityCHROMIUM)               /* 453 */ \
-  OP(BlendBarrierKHR)                          /* 454 */
+  OP(GenValuebuffersCHROMIUMImmediate)         /* 437 */ \
+  OP(DeleteValuebuffersCHROMIUMImmediate)      /* 438 */ \
+  OP(IsValuebufferCHROMIUM)                    /* 439 */ \
+  OP(BindValuebufferCHROMIUM)                  /* 440 */ \
+  OP(SubscribeValueCHROMIUM)                   /* 441 */ \
+  OP(PopulateSubscribedValuesCHROMIUM)         /* 442 */ \
+  OP(UniformValuebufferCHROMIUM)               /* 443 */ \
+  OP(BindTexImage2DCHROMIUM)                   /* 444 */ \
+  OP(ReleaseTexImage2DCHROMIUM)                /* 445 */ \
+  OP(TraceBeginCHROMIUM)                       /* 446 */ \
+  OP(TraceEndCHROMIUM)                         /* 447 */ \
+  OP(AsyncTexSubImage2DCHROMIUM)               /* 448 */ \
+  OP(AsyncTexImage2DCHROMIUM)                  /* 449 */ \
+  OP(WaitAsyncTexImage2DCHROMIUM)              /* 450 */ \
+  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 451 */ \
+  OP(DiscardFramebufferEXTImmediate)           /* 452 */ \
+  OP(LoseContextCHROMIUM)                      /* 453 */ \
+  OP(InsertSyncPointCHROMIUM)                  /* 454 */ \
+  OP(WaitSyncPointCHROMIUM)                    /* 455 */ \
+  OP(DrawBuffersEXTImmediate)                  /* 456 */ \
+  OP(DiscardBackbufferCHROMIUM)                /* 457 */ \
+  OP(ScheduleOverlayPlaneCHROMIUM)             /* 458 */ \
+  OP(MatrixLoadfCHROMIUMImmediate)             /* 459 */ \
+  OP(MatrixLoadIdentityCHROMIUM)               /* 460 */ \
+  OP(BlendBarrierKHR)                          /* 461 */
 
 enum CommandId {
   kStartPoint = cmd::kLastCommonId,  // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
index 18712010..e8631e6 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -55,6 +55,7 @@
 static std::string GetStringSrcBlendFactor(uint32_t value);
 static std::string GetStringStencilOp(uint32_t value);
 static std::string GetStringStringType(uint32_t value);
+static std::string GetStringSubscriptionTarget(uint32_t value);
 static std::string GetStringTextureBindTarget(uint32_t value);
 static std::string GetStringTextureFormat(uint32_t value);
 static std::string GetStringTextureInternalFormat(uint32_t value);
@@ -66,6 +67,7 @@
 static std::string GetStringTextureTarget(uint32_t value);
 static std::string GetStringTextureUsage(uint32_t value);
 static std::string GetStringTextureWrapMode(uint32_t value);
+static std::string GetStringValueBufferTarget(uint32_t value);
 static std::string GetStringVertexAttribType(uint32_t value);
 static std::string GetStringVertexAttribute(uint32_t value);
 static std::string GetStringVertexPointer(uint32_t value);
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 5d7cebd0..623be626e 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -3065,6 +3065,14 @@
      "GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT",
     },
     {
+     0x924C,
+     "GL_MOUSE_POSITION_CHROMIUM",
+    },
+    {
+     0x924B,
+     "GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM",
+    },
+    {
      0x924A,
      "GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM",
     },
@@ -4355,6 +4363,14 @@
       string_table, arraysize(string_table), value);
 }
 
+std::string GLES2Util::GetStringSubscriptionTarget(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_MOUSE_POSITION_CHROMIUM, "GL_MOUSE_POSITION_CHROMIUM"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
 std::string GLES2Util::GetStringTextureBindTarget(uint32_t value) {
   static const EnumToString string_table[] = {
       {GL_TEXTURE_2D, "GL_TEXTURE_2D"},
@@ -4479,6 +4495,15 @@
       string_table, arraysize(string_table), value);
 }
 
+std::string GLES2Util::GetStringValueBufferTarget(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+       "GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
 std::string GLES2Util::GetStringVertexAttribType(uint32_t value) {
   static const EnumToString string_table[] = {
       {GL_BYTE, "GL_BYTE"},
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 8293fbc..4013c3a 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -107,6 +107,8 @@
     "texture_manager.cc",
     "transfer_buffer_manager.cc",
     "transfer_buffer_manager.h",
+    "valuebuffer_manager.h",
+    "valuebuffer_manager.cc",
     "vertex_array_manager.h",
     "vertex_array_manager.cc",
     "vertex_attrib_manager.h",
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 00e7ec3..6ee57e4 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -21,6 +21,7 @@
 #include "gpu/command_buffer/service/shader_manager.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "ui/gl/gl_implementation.h"
 
 namespace gpu {
@@ -121,6 +122,7 @@
   renderbuffer_manager_.reset(new RenderbufferManager(
       memory_tracker_.get(), max_renderbuffer_size, max_samples,
       depth24_supported));
+  valuebuffer_manager_.reset(new ValuebufferManager());
   shader_manager_.reset(new ShaderManager());
 
   // Lookup GL things we need to know.
@@ -300,6 +302,11 @@
     renderbuffer_manager_.reset();
   }
 
+  if (valuebuffer_manager_ != NULL) {
+    valuebuffer_manager_->Destroy();
+    valuebuffer_manager_.reset();
+  }
+
   if (texture_manager_ != NULL) {
     texture_manager_->Destroy(have_context);
     texture_manager_.reset();
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index ae4550c..eb53252 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -34,6 +34,7 @@
 class ProgramManager;
 class ShaderManager;
 class TextureManager;
+class ValuebufferManager;
 class MemoryTracker;
 struct DisallowedFeatures;
 
@@ -126,6 +127,10 @@
     return renderbuffer_manager_.get();
   }
 
+  ValuebufferManager* valuebuffer_manager() const {
+    return valuebuffer_manager_.get();
+  }
+
   TextureManager* texture_manager() const {
     return texture_manager_.get();
   }
@@ -199,6 +204,8 @@
 
   scoped_ptr<RenderbufferManager> renderbuffer_manager_;
 
+  scoped_ptr<ValuebufferManager> valuebuffer_manager_;
+
   scoped_ptr<TextureManager> texture_manager_;
 
   scoped_ptr<ProgramManager> program_manager_;
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index 7488f57..b4e812c 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -13,6 +13,7 @@
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/query_manager.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "gpu/gpu_export.h"
@@ -200,6 +201,9 @@
   scoped_refptr<Renderbuffer> bound_renderbuffer;
   bool bound_renderbuffer_valid;
 
+  // The currently bound valuebuffer
+  scoped_refptr<Valuebuffer> bound_valuebuffer;
+
   // A map of of target -> Query for current queries
   typedef std::map<GLuint, scoped_refptr<QueryManager::Query> > QueryMap;
   QueryMap current_queries;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 9b028fd..6905d2a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -56,6 +56,7 @@
 #include "gpu/command_buffer/service/shader_translator.h"
 #include "gpu/command_buffer/service/shader_translator_cache.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
 #include "third_party/smhasher/src/City.h"
@@ -727,6 +728,8 @@
   void DeleteFramebuffersHelper(GLsizei n, const GLuint* client_ids);
   bool GenRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
   void DeleteRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
+  bool GenValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* client_ids);
+  void DeleteValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* client_ids);
   bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
   void DeleteQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
   bool GenVertexArraysOESHelper(GLsizei n, const GLuint* client_ids);
@@ -756,6 +759,10 @@
     return group_->framebuffer_manager();
   }
 
+  ValuebufferManager* valuebuffer_manager() {
+    return group_->valuebuffer_manager();
+  }
+
   ProgramManager* program_manager() {
     return group_->program_manager();
   }
@@ -944,6 +951,14 @@
   void DoCreateAndConsumeTextureCHROMIUM(GLenum target, const GLbyte* key,
     GLuint client_id);
 
+  bool DoIsValuebufferCHROMIUM(GLuint client_id);
+  void DoBindValueBufferCHROMIUM(GLenum target, GLuint valuebuffer);
+  void DoSubscribeValueCHROMIUM(GLenum target, GLenum subscription);
+  void DoPopulateSubscribedValuesCHROMIUM(GLenum target);
+  void DoUniformValueBufferCHROMIUM(GLint location,
+                                    GLenum target,
+                                    GLenum subscription);
+
   void DoBindTexImage2DCHROMIUM(
       GLenum target,
       GLint image_id);
@@ -1096,6 +1111,21 @@
     renderbuffer_manager()->RemoveRenderbuffer(client_id);
   }
 
+  // Creates a valuebuffer info for the given valuebuffer.
+  void CreateValuebuffer(GLuint client_id) {
+    return valuebuffer_manager()->CreateValuebuffer(client_id);
+  }
+
+  // Gets the valuebuffer info for a given valuebuffer.
+  Valuebuffer* GetValuebuffer(GLuint client_id) {
+    return valuebuffer_manager()->GetValuebuffer(client_id);
+  }
+
+  // Removes the valuebuffer info for the given valuebuffer.
+  void RemoveValuebuffer(GLuint client_id) {
+    valuebuffer_manager()->RemoveValuebuffer(client_id);
+  }
+
   // Gets the vertex attrib manager for the given vertex array.
   VertexAttribManager* GetVertexAttribManager(GLuint client_id) {
     VertexAttribManager* info =
@@ -1177,6 +1207,22 @@
       GLenum target,
       const char* func_name);
 
+  // Check if the current valuebuffer exists and is valid. If not generates
+  // the appropriate GL error. Returns true if the current valuebuffer is in
+  // a usable state.
+  bool CheckCurrentValuebuffer(const char* function_name);
+
+  // Check if the current valuebuffer exists and is valiud and that the
+  // value buffer is actually subscribed to the given subscription
+  bool CheckCurrentValuebufferForSubscription(GLenum subscription,
+                                              const char* function_name);
+
+  // Check if the location can be used for the given subscription target. If not
+  // generates the appropriate GL error. Returns true if the location is usable
+  bool CheckSubscriptionTarget(GLint location,
+                               GLenum subscription,
+                               const char* function_name);
+
   // Checks if the current program exists and is valid. If not generates the
   // appropriate GL error.  Returns true if the current program is in a usable
   // state.
@@ -1193,6 +1239,13 @@
   // of the draw operation are the same.
   bool CheckDrawingFeedbackLoops();
 
+  // Checks if |api_type| is valid for the given uniform
+  // If the api type is not valid generates the appropriate GL
+  // error. Returns true if |api_type| is valid for the uniform
+  bool CheckUniformForApiType(const Program::UniformInfo* info,
+                              const char* function_name,
+                              Program::UniformApiType api_type);
+
   // Gets the type of a uniform for a location in the current program. Sets GL
   // errors if the current program is not valid. Returns true if the current
   // program is valid and the location exists. Adjusts count so it
@@ -2670,6 +2723,7 @@
   DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
   DoBindFramebuffer(GL_FRAMEBUFFER, 0);
   DoBindRenderbuffer(GL_RENDERBUFFER, 0);
+  DoBindValueBufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 0);
 
   bool call_gl_clear = !surfaceless_;
 #if defined(OS_ANDROID)
@@ -2907,6 +2961,19 @@
   return true;
 }
 
+bool GLES2DecoderImpl::GenValuebuffersCHROMIUMHelper(GLsizei n,
+                                                     const GLuint* client_ids) {
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    if (GetValuebuffer(client_ids[ii])) {
+      return false;
+    }
+  }
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    CreateValuebuffer(client_ids[ii]);
+  }
+  return true;
+}
+
 bool GLES2DecoderImpl::GenTexturesHelper(GLsizei n, const GLuint* client_ids) {
   for (GLsizei ii = 0; ii < n; ++ii) {
     if (GetTexture(client_ids[ii])) {
@@ -2996,6 +3063,20 @@
   }
 }
 
+void GLES2DecoderImpl::DeleteValuebuffersCHROMIUMHelper(
+    GLsizei n,
+    const GLuint* client_ids) {
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    Valuebuffer* valuebuffer = GetValuebuffer(client_ids[ii]);
+    if (valuebuffer) {
+      if (state_.bound_valuebuffer.get() == valuebuffer) {
+        state_.bound_valuebuffer = NULL;
+      }
+      RemoveValuebuffer(client_ids[ii]);
+    }
+  }
+}
+
 void GLES2DecoderImpl::DeleteTexturesHelper(
     GLsizei n, const GLuint* client_ids) {
   bool supports_separate_framebuffer_binds =
@@ -3425,6 +3506,7 @@
   framebuffer_state_.bound_read_framebuffer = NULL;
   framebuffer_state_.bound_draw_framebuffer = NULL;
   state_.bound_renderbuffer = NULL;
+  state_.bound_valuebuffer = NULL;
 
   if (offscreen_saved_color_texture_info_.get()) {
     DCHECK(offscreen_target_color_texture_);
@@ -5722,6 +5804,55 @@
       "glTexParameteriv", GetErrorState(), texture, pname, *params);
 }
 
+bool GLES2DecoderImpl::CheckCurrentValuebuffer(const char* function_name) {
+  if (!state_.bound_valuebuffer.get()) {
+    // There is no valuebuffer bound
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+                       "no valuebuffer in use");
+    return false;
+  }
+  return true;
+}
+
+bool GLES2DecoderImpl::CheckCurrentValuebufferForSubscription(
+    GLenum subscription,
+    const char* function_name) {
+  if (!CheckCurrentValuebuffer(function_name)) {
+    return false;
+  }
+  if (!state_.bound_valuebuffer.get()->IsSubscribed(subscription)) {
+    // The valuebuffer is not subscribed to the target
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+                       "valuebuffer is not subscribed");
+    return false;
+  }
+  return true;
+}
+
+bool GLES2DecoderImpl::CheckSubscriptionTarget(GLint location,
+                                               GLenum subscription,
+                                               const char* function_name) {
+  if (!CheckCurrentProgramForUniform(location, function_name)) {
+    return false;
+  }
+  GLint real_location = -1;
+  GLint array_index = -1;
+  const Program::UniformInfo* info =
+      state_.current_program->GetUniformInfoByFakeLocation(
+          location, &real_location, &array_index);
+  if (!info) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, "unknown location");
+    return false;
+  }
+  if ((ValuebufferManager::ApiTypeForSubscriptionTarget(subscription) &
+       info->accepts_api_type) == 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+                       "wrong type for subscription");
+    return false;
+  }
+  return true;
+}
+
 bool GLES2DecoderImpl::CheckCurrentProgram(const char* function_name) {
   if (!state_.current_program.get()) {
     // The program does not exist.
@@ -5777,6 +5908,19 @@
   return false;
 }
 
+bool GLES2DecoderImpl::CheckUniformForApiType(
+    const Program::UniformInfo* info,
+    const char* function_name,
+    Program::UniformApiType api_type) {
+  DCHECK(info);
+  if ((api_type & info->accepts_api_type) == 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+                       "wrong uniform function for type");
+    return false;
+  }
+  return true;
+}
+
 bool GLES2DecoderImpl::PrepForSetUniformByLocation(
     GLint fake_location,
     const char* function_name,
@@ -5800,11 +5944,7 @@
         GL_INVALID_OPERATION, function_name, "unknown location");
     return false;
   }
-
-  if ((api_type & info->accepts_api_type) == 0) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION, function_name,
-        "wrong uniform function for type");
+  if (!CheckUniformForApiType(info, function_name, api_type)) {
     return false;
   }
   if (*count > 1 && !info->is_array) {
@@ -10696,6 +10836,73 @@
   texture_ref = texture_manager()->Consume(client_id, texture);
 }
 
+bool GLES2DecoderImpl::DoIsValuebufferCHROMIUM(GLuint client_id) {
+  const Valuebuffer* valuebuffer = GetValuebuffer(client_id);
+  return valuebuffer && valuebuffer->IsValid();
+}
+
+void GLES2DecoderImpl::DoBindValueBufferCHROMIUM(GLenum target,
+                                                 GLuint client_id) {
+  Valuebuffer* valuebuffer = NULL;
+  if (client_id != 0) {
+    valuebuffer = GetValuebuffer(client_id);
+    if (!valuebuffer) {
+      if (!group_->bind_generates_resource()) {
+        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBindValuebufferCHROMIUM",
+                           "id not generated by glBindValuebufferCHROMIUM");
+        return;
+      }
+
+      // It's a new id so make a valuebuffer for it.
+      CreateValuebuffer(client_id);
+      valuebuffer = GetValuebuffer(client_id);
+    }
+    valuebuffer->MarkAsValid();
+  }
+  state_.bound_valuebuffer = valuebuffer;
+}
+
+void GLES2DecoderImpl::DoSubscribeValueCHROMIUM(GLenum target,
+                                                GLenum subscription) {
+  if (!CheckCurrentValuebuffer("glSubscribeValueCHROMIUM")) {
+    return;
+  }
+  state_.bound_valuebuffer.get()->AddSubscription(subscription);
+}
+
+void GLES2DecoderImpl::DoPopulateSubscribedValuesCHROMIUM(GLenum target) {
+  if (!CheckCurrentValuebuffer("glPopulateSubscribedValuesCHROMIUM")) {
+    return;
+  }
+  valuebuffer_manager()->UpdateValuebufferState(state_.bound_valuebuffer.get());
+}
+
+void GLES2DecoderImpl::DoUniformValueBufferCHROMIUM(GLint location,
+                                                    GLenum target,
+                                                    GLenum subscription) {
+  if (!CheckCurrentValuebufferForSubscription(
+          subscription, "glPopulateSubscribedValuesCHROMIUM")) {
+    return;
+  }
+  if (!CheckSubscriptionTarget(location, subscription,
+                               "glPopulateSubscribedValuesCHROMIUM")) {
+    return;
+  }
+  const ValueState* state =
+      state_.bound_valuebuffer.get()->GetState(subscription);
+  if (state) {
+    switch (subscription) {
+      case GL_MOUSE_POSITION_CHROMIUM:
+        DoUniform2iv(location, 1, state->int_value);
+        break;
+      default:
+        NOTREACHED() << "Unhandled uniform subscription target "
+                     << subscription;
+        break;
+    }
+  }
+}
+
 void GLES2DecoderImpl::DoInsertEventMarkerEXT(
     GLsizei length, const GLchar* marker) {
   if (!marker) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 02d914f..d05b9167 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -3115,6 +3115,146 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGenValuebuffersCHROMIUMImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::GenValuebuffersCHROMIUMImmediate& c =
+      *static_cast<const gles2::cmds::GenValuebuffersCHROMIUMImmediate*>(
+          cmd_data);
+  (void)c;
+  GLsizei n = static_cast<GLsizei>(c.n);
+  uint32_t data_size;
+  if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+    return error::kOutOfBounds;
+  }
+  GLuint* buffers =
+      GetImmediateDataAs<GLuint*>(c, data_size, immediate_data_size);
+  if (buffers == NULL) {
+    return error::kOutOfBounds;
+  }
+  if (!GenValuebuffersCHROMIUMHelper(n, buffers)) {
+    return error::kInvalidArguments;
+  }
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteValuebuffersCHROMIUMImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::DeleteValuebuffersCHROMIUMImmediate& c =
+      *static_cast<const gles2::cmds::DeleteValuebuffersCHROMIUMImmediate*>(
+          cmd_data);
+  (void)c;
+  GLsizei n = static_cast<GLsizei>(c.n);
+  uint32_t data_size;
+  if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+    return error::kOutOfBounds;
+  }
+  const GLuint* valuebuffers =
+      GetImmediateDataAs<const GLuint*>(c, data_size, immediate_data_size);
+  if (valuebuffers == NULL) {
+    return error::kOutOfBounds;
+  }
+  DeleteValuebuffersCHROMIUMHelper(n, valuebuffers);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsValuebufferCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::IsValuebufferCHROMIUM& c =
+      *static_cast<const gles2::cmds::IsValuebufferCHROMIUM*>(cmd_data);
+  (void)c;
+  GLuint valuebuffer = c.valuebuffer;
+  typedef cmds::IsValuebufferCHROMIUM::Result Result;
+  Result* result_dst = GetSharedMemoryAs<Result*>(
+      c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+  if (!result_dst) {
+    return error::kOutOfBounds;
+  }
+  *result_dst = DoIsValuebufferCHROMIUM(valuebuffer);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindValuebufferCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::BindValuebufferCHROMIUM& c =
+      *static_cast<const gles2::cmds::BindValuebufferCHROMIUM*>(cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  GLuint valuebuffer = c.valuebuffer;
+  if (!validators_->value_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glBindValuebufferCHROMIUM", target,
+                                    "target");
+    return error::kNoError;
+  }
+  DoBindValueBufferCHROMIUM(target, valuebuffer);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleSubscribeValueCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::SubscribeValueCHROMIUM& c =
+      *static_cast<const gles2::cmds::SubscribeValueCHROMIUM*>(cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  GLenum subscription = static_cast<GLenum>(c.subscription);
+  if (!validators_->value_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glSubscribeValueCHROMIUM", target,
+                                    "target");
+    return error::kNoError;
+  }
+  if (!validators_->subscription_target.IsValid(subscription)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glSubscribeValueCHROMIUM", subscription,
+                                    "subscription");
+    return error::kNoError;
+  }
+  DoSubscribeValueCHROMIUM(target, subscription);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandlePopulateSubscribedValuesCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::PopulateSubscribedValuesCHROMIUM& c =
+      *static_cast<const gles2::cmds::PopulateSubscribedValuesCHROMIUM*>(
+          cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  if (!validators_->value_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glPopulateSubscribedValuesCHROMIUM",
+                                    target, "target");
+    return error::kNoError;
+  }
+  DoPopulateSubscribedValuesCHROMIUM(target);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformValuebufferCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::UniformValuebufferCHROMIUM& c =
+      *static_cast<const gles2::cmds::UniformValuebufferCHROMIUM*>(cmd_data);
+  (void)c;
+  GLint location = static_cast<GLint>(c.location);
+  GLenum target = static_cast<GLenum>(c.target);
+  GLenum subscription = static_cast<GLenum>(c.subscription);
+  if (!validators_->value_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glUniformValuebufferCHROMIUM", target,
+                                    "target");
+    return error::kNoError;
+  }
+  if (!validators_->subscription_target.IsValid(subscription)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glUniformValuebufferCHROMIUM",
+                                    subscription, "subscription");
+    return error::kNoError;
+  }
+  DoUniformValueBufferCHROMIUM(location, target, subscription);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleBindTexImage2DCHROMIUM(
     uint32_t immediate_data_size,
     const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
index 95c2027c..9021aab 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
@@ -692,6 +692,31 @@
 // TODO(gman): ConsumeTextureCHROMIUMImmediate
 // TODO(gman): CreateAndConsumeTextureCHROMIUMImmediate
 // TODO(gman): BindUniformLocationCHROMIUMBucket
+// TODO(gman): GenValuebuffersCHROMIUMImmediate
+// TODO(gman): DeleteValuebuffersCHROMIUMImmediate
+
+TEST_P(GLES2DecoderTest2, IsValuebufferCHROMIUMValidArgs) {
+  SpecializedSetup<cmds::IsValuebufferCHROMIUM, 0>(true);
+  cmds::IsValuebufferCHROMIUM cmd;
+  cmd.Init(client_valuebuffer_id_, shared_memory_id_, shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, IsValuebufferCHROMIUMInvalidArgsBadSharedMemoryId) {
+  SpecializedSetup<cmds::IsValuebufferCHROMIUM, 0>(false);
+  cmds::IsValuebufferCHROMIUM cmd;
+  cmd.Init(client_valuebuffer_id_, kInvalidSharedMemoryId,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_valuebuffer_id_, shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+// TODO(gman): BindValuebufferCHROMIUM
+// TODO(gman): SubscribeValueCHROMIUM
+// TODO(gman): PopulateSubscribedValuesCHROMIUM
+// TODO(gman): UniformValuebufferCHROMIUM
 // TODO(gman): BindTexImage2DCHROMIUM
 // TODO(gman): ReleaseTexImage2DCHROMIUM
 // TODO(gman): TraceBeginCHROMIUM
@@ -705,13 +730,4 @@
 
 // TODO(gman): WaitAllAsyncTexImage2DCHROMIUM
 
-// TODO(gman): LoseContextCHROMIUM
-// TODO(gman): InsertSyncPointCHROMIUM
-
-// TODO(gman): WaitSyncPointCHROMIUM
-
-// TODO(gman): DrawBuffersEXTImmediate
-// TODO(gman): DiscardBackbufferCHROMIUM
-
-// TODO(gman): ScheduleOverlayPlaneCHROMIUM
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
index 7e93f36..1c98b68 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -12,4 +12,13 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
 
+// TODO(gman): LoseContextCHROMIUM
+// TODO(gman): InsertSyncPointCHROMIUM
+
+// TODO(gman): WaitSyncPointCHROMIUM
+
+// TODO(gman): DrawBuffersEXTImmediate
+// TODO(gman): DiscardBackbufferCHROMIUM
+
+// TODO(gman): ScheduleOverlayPlaneCHROMIUM
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 136834d..36afe38 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -96,6 +96,7 @@
       client_fragment_shader_id_(122),
       client_query_id_(123),
       client_vertexarray_id_(124),
+      client_valuebuffer_id_(125),
       service_renderbuffer_id_(0),
       service_renderbuffer_valid_(false),
       ignore_cached_state_for_test_(GetParam()),
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 1507440..1a2b54a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -19,6 +19,7 @@
 #include "gpu/command_buffer/service/shader_manager.h"
 #include "gpu/command_buffer/service/test_helper.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_context_stub_with_extensions.h"
@@ -122,6 +123,10 @@
     return group_->program_manager()->GetProgram(client_id);
   }
 
+  Valuebuffer* GetValuebuffer(GLuint client_id) {
+    return group_->valuebuffer_manager()->GetValuebuffer(client_id);
+  }
+
   QueryManager::Query* GetQueryInfo(GLuint client_id) {
     return decoder_->GetQueryManager()->GetQuery(client_id);
   }
@@ -136,6 +141,10 @@
     return group_->program_manager();
   }
 
+  ValuebufferManager* valuebuffer_manager() {
+    return group_->valuebuffer_manager();
+  }
+
   ImageManager* GetImageManager() { return decoder_->GetImageManager(); }
 
   void DoCreateProgram(GLuint client_id, GLuint service_id);
@@ -514,6 +523,7 @@
   GLuint client_fragment_shader_id_;
   GLuint client_query_id_;
   GLuint client_vertexarray_id_;
+  GLuint client_valuebuffer_id_;
 
   uint32 shared_memory_id_;
   uint32 shared_memory_offset_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc
new file mode 100644
index 0000000..012d5041
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+#include "base/command_line.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h"
+
+#include "gpu/command_buffer/service/test_helper.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+#include "ui/gl/gl_surface_stub.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+
+namespace gpu {
+namespace gles2 {
+
+using namespace cmds;
+
+TEST_P(GLES2DecoderWithShaderTest, ValuebufferBasic) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  BindValuebufferCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  SubscribeValueCHROMIUM cmd2;
+  cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  PopulateSubscribedValuesCHROMIUM cmd3;
+  cmd3.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+  EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(1);
+  UniformValuebufferCHROMIUM cmd4;
+  cmd4.Init(kUniform2FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+            GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd4));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, SubscribeValuebufferNotBound) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  SubscribeValueCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, PopulateValuebufferNoSubscription) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  BindValuebufferCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  PopulateSubscribedValuesCHROMIUM cmd2;
+  cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  EXPECT_EQ(GL_NONE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, UniformValuebufferNoState) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  BindValuebufferCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  SubscribeValueCHROMIUM cmd2;
+  cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(0);
+  UniformValuebufferCHROMIUM cmd3;
+  cmd3.Init(kUniform2FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+            GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+  EXPECT_EQ(GL_NONE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, UniformValuebufferInvalidLocation) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  BindValuebufferCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  SubscribeValueCHROMIUM cmd2;
+  cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  PopulateSubscribedValuesCHROMIUM cmd3;
+  cmd3.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+  EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(0);
+  UniformValuebufferCHROMIUM cmd4;
+  cmd4.Init(kUniform1FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+            GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd4));
+  EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+}  // namespace gles2
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index de84037..c72bcf8 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -56,6 +56,7 @@
 ValueValidator<GLenum> src_blend_factor;
 ValueValidator<GLenum> stencil_op;
 ValueValidator<GLenum> string_type;
+ValueValidator<GLenum> subscription_target;
 ValueValidator<GLenum> texture_bind_target;
 ValueValidator<GLenum> texture_format;
 ValueValidator<GLenum> texture_internal_format;
@@ -67,6 +68,7 @@
 ValueValidator<GLenum> texture_target;
 ValueValidator<GLenum> texture_usage;
 ValueValidator<GLenum> texture_wrap_mode;
+ValueValidator<GLenum> value_buffer_target;
 ValueValidator<GLint> vertex_attrib_size;
 ValueValidator<GLenum> vertex_attrib_type;
 ValueValidator<GLenum> vertex_attribute;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 790b9b3..6a646ac 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -413,6 +413,10 @@
     GL_EXTENSIONS,
 };
 
+static const GLenum valid_subscription_target_table[] = {
+    GL_MOUSE_POSITION_CHROMIUM,
+};
+
 static const GLenum valid_texture_bind_target_table[] = {
     GL_TEXTURE_2D,
     GL_TEXTURE_CUBE_MAP,
@@ -493,6 +497,10 @@
     GL_REPEAT,
 };
 
+static const GLenum valid_value_buffer_target_table[] = {
+    GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+};
+
 static const GLint valid_vertex_attrib_size_table[] = {
     1,
     2,
@@ -593,6 +601,8 @@
                        arraysize(valid_src_blend_factor_table)),
       stencil_op(valid_stencil_op_table, arraysize(valid_stencil_op_table)),
       string_type(valid_string_type_table, arraysize(valid_string_type_table)),
+      subscription_target(valid_subscription_target_table,
+                          arraysize(valid_subscription_target_table)),
       texture_bind_target(valid_texture_bind_target_table,
                           arraysize(valid_texture_bind_target_table)),
       texture_format(valid_texture_format_table,
@@ -616,6 +626,8 @@
                     arraysize(valid_texture_usage_table)),
       texture_wrap_mode(valid_texture_wrap_mode_table,
                         arraysize(valid_texture_wrap_mode_table)),
+      value_buffer_target(valid_value_buffer_target_table,
+                          arraysize(valid_value_buffer_target_table)),
       vertex_attrib_size(valid_vertex_attrib_size_table,
                          arraysize(valid_vertex_attrib_size_table)),
       vertex_attrib_type(valid_vertex_attrib_type_table,
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 7bc72ded..f3c447cb 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -193,8 +193,7 @@
       memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
 }
 
-Program::Program(
-    ProgramManager* manager, GLuint service_id)
+Program::Program(ProgramManager* manager, GLuint service_id)
     : manager_(manager),
       use_count_(0),
       max_attrib_name_length_(0),
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index dbe9c14..2f5deae 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -39,6 +39,7 @@
   };
 
   enum UniformApiType {
+    kUniformNone = 0,
     kUniform1i = 1 << 0,
     kUniform2i = 1 << 1,
     kUniform3i = 1 << 2,
diff --git a/gpu/command_buffer/service/valuebuffer_manager.cc b/gpu/command_buffer/service/valuebuffer_manager.cc
new file mode 100644
index 0000000..eb4db09
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
+
+#include "gpu/command_buffer/service/program_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+Valuebuffer::Valuebuffer(ValuebufferManager* manager, GLuint client_id)
+    : manager_(manager), client_id_(client_id), has_been_bound_(false) {
+  manager_->StartTracking(this);
+}
+
+Valuebuffer::~Valuebuffer() {
+  if (manager_) {
+    manager_->StopTracking(this);
+    manager_ = NULL;
+  }
+}
+
+void Valuebuffer::AddSubscription(GLenum subscription) {
+  subscriptions_.insert(subscription);
+}
+
+void Valuebuffer::RemoveSubscription(GLenum subscription) {
+  subscriptions_.erase(subscription);
+}
+
+bool Valuebuffer::IsSubscribed(GLenum subscription) {
+  return subscriptions_.find(subscription) != subscriptions_.end();
+}
+
+const ValueState *Valuebuffer::GetState(GLenum target) const {
+  StateMap::const_iterator it = active_state_map_.find(target);
+  return it != active_state_map_.end() ? &it->second : NULL;
+}
+
+void Valuebuffer::UpdateState(const StateMap& pending_state) {
+  for (SubscriptionSet::const_iterator it = subscriptions_.begin();
+       it != subscriptions_.end(); ++it) {
+    StateMap::const_iterator pending_state_it = pending_state.find((*it));
+    if (pending_state_it != pending_state.end()) {
+      active_state_map_[pending_state_it->first] = pending_state_it->second;
+    }
+  }
+}
+
+ValuebufferManager::ValuebufferManager()
+    : valuebuffer_count_(0) {
+}
+
+ValuebufferManager::~ValuebufferManager() {
+  DCHECK(valuebuffer_map_.empty());
+  DCHECK(pending_state_map_.empty());
+  // If this triggers, that means something is keeping a reference to
+  // a Valuebuffer belonging to this.
+  CHECK_EQ(valuebuffer_count_, 0u);
+}
+
+void ValuebufferManager::Destroy() {
+  valuebuffer_map_.clear();
+  pending_state_map_.clear();
+}
+
+void ValuebufferManager::StartTracking(Valuebuffer* /* valuebuffer */) {
+  ++valuebuffer_count_;
+}
+
+void ValuebufferManager::StopTracking(Valuebuffer* /* valuebuffer */) {
+  --valuebuffer_count_;
+}
+
+void ValuebufferManager::CreateValuebuffer(GLuint client_id) {
+  scoped_refptr<Valuebuffer> valuebuffer(new Valuebuffer(this, client_id));
+  std::pair<ValuebufferMap::iterator, bool> result =
+      valuebuffer_map_.insert(std::make_pair(client_id, valuebuffer));
+  DCHECK(result.second);
+}
+
+Valuebuffer* ValuebufferManager::GetValuebuffer(GLuint client_id) {
+  ValuebufferMap::iterator it = valuebuffer_map_.find(client_id);
+  return it != valuebuffer_map_.end() ? it->second.get() : NULL;
+}
+
+void ValuebufferManager::RemoveValuebuffer(GLuint client_id) {
+  ValuebufferMap::iterator it = valuebuffer_map_.find(client_id);
+  if (it != valuebuffer_map_.end()) {
+    Valuebuffer* valuebuffer = it->second.get();
+    valuebuffer->MarkAsDeleted();
+    valuebuffer_map_.erase(it);
+  }
+}
+
+void ValuebufferManager::UpdateValuebufferState(Valuebuffer* valuebuffer) {
+  DCHECK(valuebuffer);
+  valuebuffer->UpdateState(pending_state_map_);
+}
+
+void ValuebufferManager::UpdateValueState(
+    GLenum target, const ValueState& state) {
+  pending_state_map_[target] = state;
+}
+
+uint32 ValuebufferManager::ApiTypeForSubscriptionTarget(GLenum target) {
+  switch (target) {
+    case GL_MOUSE_POSITION_CHROMIUM:
+      return Program::kUniform2i;
+  }
+  NOTREACHED() << "Unhandled uniform subscription target " << target;
+  return Program::kUniformNone;
+}
+
+}  // namespace gles2
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/valuebuffer_manager.h b/gpu/command_buffer/service/valuebuffer_manager.h
new file mode 100644
index 0000000..3cc4ac1
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ValuebufferManager;
+
+union ValueState {
+  float float_value[4];
+  int int_value[4];
+};
+
+class GPU_EXPORT Valuebuffer : public base::RefCounted<Valuebuffer> {
+ public:
+  Valuebuffer(ValuebufferManager* manager, GLuint client_id);
+
+  GLuint client_id() const { return client_id_; }
+
+  bool IsDeleted() const { return client_id_ == 0; }
+
+  void MarkAsValid() { has_been_bound_ = true; }
+
+  bool IsValid() const { return has_been_bound_ && !IsDeleted(); }
+
+  void AddSubscription(GLenum subscription);
+  void RemoveSubscription(GLenum subscription);
+
+  // Returns true if this Valuebuffer is subscribed to subscription
+  bool IsSubscribed(GLenum subscription);
+
+  // Returns the active state for a given target in this Valuebuffer
+  // returns NULL if target state doesn't exist
+  const ValueState* GetState(GLenum target) const;
+
+ private:
+  friend class ValuebufferManager;
+  friend class base::RefCounted<Valuebuffer>;
+
+  typedef base::hash_map<GLenum, ValueState> StateMap;
+  typedef base::hash_set<GLenum> SubscriptionSet;
+
+  ~Valuebuffer();
+
+  void UpdateState(const StateMap& pending_state);
+
+  void MarkAsDeleted() { client_id_ = 0; }
+
+  // ValuebufferManager that owns this Valuebuffer.
+  ValuebufferManager* manager_;
+
+  // Client side Valuebuffer id.
+  GLuint client_id_;
+
+  // Whether this Valuebuffer has ever been bound.
+  bool has_been_bound_;
+
+  SubscriptionSet subscriptions_;
+
+  StateMap active_state_map_;
+};
+
+class GPU_EXPORT ValuebufferManager {
+ public:
+  ValuebufferManager();
+  ~ValuebufferManager();
+
+  // Must call before destruction.
+  void Destroy();
+
+  // Creates a Valuebuffer for the given Valuebuffer ids.
+  void CreateValuebuffer(GLuint client_id);
+
+  // Gets the Valuebuffer for the given Valuebuffer id.
+  Valuebuffer* GetValuebuffer(GLuint client_id);
+
+  // Removes a Valuebuffer for the given Valuebuffer id.
+  void RemoveValuebuffer(GLuint client_id);
+
+  // Updates the value state for the given Valuebuffer
+  void UpdateValuebufferState(Valuebuffer* valuebuffer);
+
+  // Gets the state for the given subscription target
+  void UpdateValueState(GLenum target, const ValueState& state);
+
+  static uint32 ApiTypeForSubscriptionTarget(GLenum target);
+
+ private:
+  friend class Valuebuffer;
+
+  typedef base::hash_map<GLuint, scoped_refptr<Valuebuffer>> ValuebufferMap;
+
+  void StartTracking(Valuebuffer* valuebuffer);
+  void StopTracking(Valuebuffer* valuebuffer);
+
+  // Counts the number of Valuebuffer allocated with 'this' as its manager.
+  // Allows to check no Valuebuffer will outlive this.
+  unsigned valuebuffer_count_;
+
+  // Info for each Valuebuffer in the system.
+  ValuebufferMap valuebuffer_map_;
+
+  // Current value state in the system
+  Valuebuffer::StateMap pending_state_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValuebufferManager);
+};
+
+}  // namespace gles2
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
diff --git a/gpu/command_buffer/service/valuebuffer_manager_unittest.cc b/gpu/command_buffer/service/valuebuffer_manager_unittest.cc
new file mode 100644
index 0000000..ead5df5
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gpu_service_test.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_mock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ValuebufferManagerTest : public GpuServiceTest {
+ public:
+  ValuebufferManagerTest() : manager_() {}
+  ~ValuebufferManagerTest() override { manager_.Destroy(); }
+
+ protected:
+  ValuebufferManager manager_;
+};
+
+TEST_F(ValuebufferManagerTest, Basic) {
+  const GLuint kClient1Id = 1;
+  const GLuint kClient2Id = 2;
+  // Check we can create a Valuebuffer
+  manager_.CreateValuebuffer(kClient1Id);
+  Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer0 != NULL);
+  EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+  // Check we get nothing for a non-existent Valuebuffer.
+  // Check trying to a remove non-existent Valuebuffer does not crash
+  manager_.RemoveValuebuffer(kClient2Id);
+  // Check we can't get the renderbuffer after we remove it.
+  manager_.RemoveValuebuffer(kClient1Id);
+  EXPECT_TRUE(manager_.GetValuebuffer(kClient1Id) == NULL);
+}
+
+TEST_F(ValuebufferManagerTest, Destroy) {
+  const GLuint kClient1Id = 1;
+  // Check we can create Valuebuffer.
+  manager_.CreateValuebuffer(kClient1Id);
+  Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer0 != NULL);
+  EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+  manager_.Destroy();
+  // Check the resources were released.
+  Valuebuffer* valuebuffer1 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer1 == NULL);
+}
+
+TEST_F(ValuebufferManagerTest, ValueBuffer) {
+  const GLuint kClient1Id = 1;
+  // Check we can create a Valuebuffer
+  manager_.CreateValuebuffer(kClient1Id);
+  Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer0 != NULL);
+  EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+  EXPECT_FALSE(valuebuffer0->IsValid());
+}
+
+TEST_F(ValuebufferManagerTest, UpdateState) {
+  const GLuint kClient1Id = 1;
+  ValueState valuestate1;
+  valuestate1.int_value[0] = 111;
+  ValueState valuestate2;
+  valuestate2.int_value[0] = 222;
+  manager_.CreateValuebuffer(kClient1Id);
+  Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer0 != NULL);
+  EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+  valuebuffer0->AddSubscription(GL_MOUSE_POSITION_CHROMIUM);
+  ASSERT_TRUE(valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM) == NULL);
+  manager_.UpdateValueState(GL_MOUSE_POSITION_CHROMIUM, valuestate1);
+  manager_.UpdateValuebufferState(valuebuffer0);
+  const ValueState* new_state1 =
+      valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM);
+  ASSERT_TRUE(new_state1 != NULL);
+  ASSERT_TRUE(new_state1->int_value[0] == 111);
+  // Ensure state changes
+  manager_.UpdateValueState(GL_MOUSE_POSITION_CHROMIUM, valuestate2);
+  manager_.UpdateValuebufferState(valuebuffer0);
+  const ValueState* new_state2 =
+      valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM);
+  ASSERT_TRUE(new_state2 != NULL);
+  ASSERT_TRUE(new_state2->int_value[0] == 222);
+}
+
+}  // namespace gles2
+}  // namespace gpu
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index f1ed489..13ffe94 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -125,6 +125,8 @@
     'command_buffer/service/texture_manager.cc',
     'command_buffer/service/transfer_buffer_manager.cc',
     'command_buffer/service/transfer_buffer_manager.h',
+    'command_buffer/service/valuebuffer_manager.h',
+    'command_buffer/service/valuebuffer_manager.cc',
     'command_buffer/service/vertex_array_manager.h',
     'command_buffer/service/vertex_array_manager.cc',
     'command_buffer/service/vertex_attrib_manager.h',
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 0878a1d3..3273b268 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -232,6 +232,7 @@
         'command_buffer/service/gles2_cmd_decoder_unittest_programs.cc',
         'command_buffer/service/gles2_cmd_decoder_unittest_textures.cc',
         'command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc',
+        'command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc',
         'command_buffer/service/gl_surface_mock.cc',
         'command_buffer/service/gl_surface_mock.h',
         'command_buffer/service/gpu_scheduler_unittest.cc',
@@ -252,6 +253,7 @@
         'command_buffer/service/test_helper.h',
         'command_buffer/service/texture_manager_unittest.cc',
         'command_buffer/service/transfer_buffer_manager_unittest.cc',
+        'command_buffer/service/valuebuffer_manager_unittest.cc',
         'command_buffer/service/vertex_attrib_manager_unittest.cc',
         'command_buffer/service/vertex_array_manager_unittest.cc',
         'command_buffer/service/gpu_tracer_unittest.cc',
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index dd737f41..aea47fc 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -143,6 +143,10 @@
 #define GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM         0x9249
 #define GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM         0x924A
 
+// GL_CHROMIUM_subscribe_uniforms
+#define GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM             0x924B
+#define GL_MOUSE_POSITION_CHROMIUM                       0x924C
+
 // GL_OES_texure_3D
 #define GL_SAMPLER_3D_OES                                0x8B5F
 
diff --git a/webkit/common/gpu/webgraphicscontext3d_impl.cc b/webkit/common/gpu/webgraphicscontext3d_impl.cc
index 3625de5a..9e425097 100644
--- a/webkit/common/gpu/webgraphicscontext3d_impl.cc
+++ b/webkit/common/gpu/webgraphicscontext3d_impl.cc
@@ -846,6 +846,47 @@
                   CreateAndConsumeTextureCHROMIUM,
                   WGC3Denum, const WGC3Dbyte*, WebGLId)
 
+DELEGATE_TO_GL_2(genValuebuffersCHROMIUM,
+                 GenValuebuffersCHROMIUM,
+                 WGC3Dsizei,
+                 WebGLId*);
+
+WebGLId WebGraphicsContext3DImpl::createValuebufferCHROMIUM() {
+  GLuint o;
+  gl_->GenValuebuffersCHROMIUM(1, &o);
+  return o;
+}
+
+DELEGATE_TO_GL_2(deleteValuebuffersCHROMIUM,
+                 DeleteValuebuffersCHROMIUM,
+                 WGC3Dsizei,
+                 WebGLId*);
+
+void WebGraphicsContext3DImpl::deleteValuebufferCHROMIUM(WebGLId valuebuffer) {
+  gl_->DeleteValuebuffersCHROMIUM(1, &valuebuffer);
+}
+
+DELEGATE_TO_GL_1RB(isValuebufferCHROMIUM,
+                   IsValuebufferCHROMIUM,
+                   WebGLId,
+                   WGC3Dboolean)
+DELEGATE_TO_GL_2(bindValuebufferCHROMIUM,
+                 BindValuebufferCHROMIUM,
+                 WGC3Denum,
+                 WebGLId)
+DELEGATE_TO_GL_2(subscribeValueCHROMIUM,
+                 SubscribeValueCHROMIUM,
+                 WGC3Denum,
+                 WGC3Denum);
+DELEGATE_TO_GL_1(populateSubscribedValuesCHROMIUM,
+                 PopulateSubscribedValuesCHROMIUM,
+                 WGC3Denum);
+DELEGATE_TO_GL_3(uniformValuebufferCHROMIUM,
+                 UniformValuebufferCHROMIUM,
+                 WGC3Dint,
+                 WGC3Denum,
+                 WGC3Denum);
+
 void WebGraphicsContext3DImpl::insertEventMarkerEXT(
     const WGC3Dchar* marker) {
   gl_->InsertEventMarkerEXT(0, marker);
diff --git a/webkit/common/gpu/webgraphicscontext3d_impl.h b/webkit/common/gpu/webgraphicscontext3d_impl.h
index ee3cb36..3ed0dd9 100644
--- a/webkit/common/gpu/webgraphicscontext3d_impl.h
+++ b/webkit/common/gpu/webgraphicscontext3d_impl.h
@@ -483,6 +483,18 @@
   virtual WebGLId createAndConsumeTextureCHROMIUM(WGC3Denum target,
                                       const WGC3Dbyte* mailbox);
 
+  virtual void genValuebuffersCHROMIUM(WGC3Dsizei count, WebGLId* ids);
+  virtual WebGLId createValuebufferCHROMIUM();
+  virtual void deleteValuebuffersCHROMIUM(WGC3Dsizei count, WebGLId* ids);
+  virtual void deleteValuebufferCHROMIUM(WebGLId);
+  virtual void bindValuebufferCHROMIUM(WGC3Denum target, WebGLId valuebuffer);
+  virtual WGC3Dboolean isValuebufferCHROMIUM(WebGLId renderbuffer);
+  virtual void subscribeValueCHROMIUM(WGC3Denum target, WGC3Denum subscription);
+  virtual void populateSubscribedValuesCHROMIUM(WGC3Denum target);
+  virtual void uniformValuebufferCHROMIUM(WGC3Dint location,
+                                          WGC3Denum target,
+                                          WGC3Denum subscription);
+
   virtual void insertEventMarkerEXT(const WGC3Dchar* marker);
   virtual void pushGroupMarkerEXT(const WGC3Dchar* marker);
   virtual void popGroupMarkerEXT();