Update from https://crrev.com/316786

List of manually-modified files:
gpu/command_buffer/service/in_process_command_buffer.cc
examples/sample_app/BUILD.gn
examples/sample_app/spinning_cube.cc
mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
mojo/cc/context_provider_mojo.cc
mojo/cc/context_provider_mojo.h
mojo/common/trace_controller_impl.cc
mojo/gles2/command_buffer_client_impl.cc
mojo/gles2/command_buffer_client_impl.h
services/gles2/gpu_impl.cc
shell/android/apk/src/org/chromium/mojo/shell/MojoShellApplication.java
sky/engine/core/dom/Node.cpp
sky/shell/apk/src/org/domokit/sky/shell/SkyShellApplication.java
ui/events/latency_info.cc
ui/gfx/transform.cc
ui/gfx/transform.h
ui/gfx/transform_util.cc
ui/gfx/transform_util.h

Review URL: https://codereview.chromium.org/935333002
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 0896026..e1d5348 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -47,10 +47,10 @@
 source_set("test_support") {
   testonly = true
   sources = [
-    "command_buffer/service/gles2_cmd_decoder_mock.cc",
-    "command_buffer/service/error_state_mock.cc",
     "command_buffer/client/gles2_interface_stub.cc",
     "command_buffer/client/gles2_interface_stub.h",
+    "command_buffer/service/error_state_mock.cc",
+    "command_buffer/service/gles2_cmd_decoder_mock.cc",
   ]
 
   public_deps = [
@@ -156,10 +156,10 @@
       "command_buffer/common/id_allocator_test.cc",
       "command_buffer/common/trace_event.h",
       "command_buffer/common/unittest_main.cc",
-      "command_buffer/service/async_pixel_transfer_delegate_mock.h",
       "command_buffer/service/async_pixel_transfer_delegate_mock.cc",
-      "command_buffer/service/async_pixel_transfer_manager_mock.h",
+      "command_buffer/service/async_pixel_transfer_delegate_mock.h",
       "command_buffer/service/async_pixel_transfer_manager_mock.cc",
+      "command_buffer/service/async_pixel_transfer_manager_mock.h",
       "command_buffer/service/buffer_manager_unittest.cc",
       "command_buffer/service/cmd_parser_test.cc",
       "command_buffer/service/command_buffer_service_unittest.cc",
@@ -167,6 +167,8 @@
       "command_buffer/service/context_group_unittest.cc",
       "command_buffer/service/feature_info_unittest.cc",
       "command_buffer/service/framebuffer_manager_unittest.cc",
+      "command_buffer/service/gl_surface_mock.cc",
+      "command_buffer/service/gl_surface_mock.h",
       "command_buffer/service/gles2_cmd_decoder_unittest.cc",
       "command_buffer/service/gles2_cmd_decoder_unittest.h",
       "command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h",
@@ -177,6 +179,7 @@
       "command_buffer/service/gles2_cmd_decoder_unittest_3.cc",
       "command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h",
       "command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc",
+      "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc",
       "command_buffer/service/gles2_cmd_decoder_unittest_base.cc",
       "command_buffer/service/gles2_cmd_decoder_unittest_base.h",
       "command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc",
@@ -185,33 +188,30 @@
       "command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc",
       "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",
       "command_buffer/service/gpu_service_test.cc",
       "command_buffer/service/gpu_service_test.h",
+      "command_buffer/service/gpu_tracer_unittest.cc",
       "command_buffer/service/id_manager_unittest.cc",
       "command_buffer/service/mailbox_manager_unittest.cc",
       "command_buffer/service/memory_program_cache_unittest.cc",
       "command_buffer/service/mocks.cc",
       "command_buffer/service/mocks.h",
+      "command_buffer/service/program_cache_unittest.cc",
       "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",
       "command_buffer/service/shader_manager_unittest.cc",
-      "command_buffer/service/shader_translator_unittest.cc",
       "command_buffer/service/shader_translator_cache_unittest.cc",
+      "command_buffer/service/shader_translator_unittest.cc",
       "command_buffer/service/test_helper.cc",
       "command_buffer/service/test_helper.h",
       "command_buffer/service/texture_manager_unittest.cc",
       "command_buffer/service/transfer_buffer_manager_unittest.cc",
-      "command_buffer/service/vertex_attrib_manager_unittest.cc",
+      "command_buffer/service/valuebuffer_manager_unittest.cc",
       "command_buffer/service/vertex_array_manager_unittest.cc",
-      "command_buffer/service/gpu_tracer_unittest.cc",
+      "command_buffer/service/vertex_attrib_manager_unittest.cc",
       "config/gpu_blacklist_unittest.cc",
       "config/gpu_control_list_entry_unittest.cc",
       "config/gpu_control_list_number_info_unittest.cc",
@@ -247,6 +247,7 @@
 
   test("gpu_perftests") {
     sources = [
+      "perftests/measurements.cc",
       "perftests/run_all_tests.cc",
       "perftests/texture_upload_perftest.cc",
     ]
@@ -254,6 +255,7 @@
     deps = [
       "//base",
       "//base/test:test_support",
+      "//gpu/command_buffer/service",
       "//testing/gtest",
       "//testing/perf",
       "//ui/gfx/geometry",
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index 9d3a0f9..a36a026 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -86,7 +86,9 @@
 #define glGenTransformFeedbacks GLES2_GET_FUN(GenTransformFeedbacks)
 #define glGetActiveAttrib GLES2_GET_FUN(GetActiveAttrib)
 #define glGetActiveUniform GLES2_GET_FUN(GetActiveUniform)
+#define glGetActiveUniformBlockiv GLES2_GET_FUN(GetActiveUniformBlockiv)
 #define glGetActiveUniformBlockName GLES2_GET_FUN(GetActiveUniformBlockName)
+#define glGetActiveUniformsiv GLES2_GET_FUN(GetActiveUniformsiv)
 #define glGetAttachedShaders GLES2_GET_FUN(GetAttachedShaders)
 #define glGetAttribLocation GLES2_GET_FUN(GetAttribLocation)
 #define glGetBooleanv GLES2_GET_FUN(GetBooleanv)
@@ -110,9 +112,11 @@
 #define glGetString GLES2_GET_FUN(GetString)
 #define glGetTexParameterfv GLES2_GET_FUN(GetTexParameterfv)
 #define glGetTexParameteriv GLES2_GET_FUN(GetTexParameteriv)
+#define glGetTransformFeedbackVarying GLES2_GET_FUN(GetTransformFeedbackVarying)
 #define glGetUniformBlockIndex GLES2_GET_FUN(GetUniformBlockIndex)
 #define glGetUniformfv GLES2_GET_FUN(GetUniformfv)
 #define glGetUniformiv GLES2_GET_FUN(GetUniformiv)
+#define glGetUniformIndices GLES2_GET_FUN(GetUniformIndices)
 #define glGetUniformLocation GLES2_GET_FUN(GetUniformLocation)
 #define glGetVertexAttribfv GLES2_GET_FUN(GetVertexAttribfv)
 #define glGetVertexAttribiv GLES2_GET_FUN(GetVertexAttribiv)
@@ -191,6 +195,7 @@
 #define glUniform4iv GLES2_GET_FUN(Uniform4iv)
 #define glUniform4ui GLES2_GET_FUN(Uniform4ui)
 #define glUniform4uiv GLES2_GET_FUN(Uniform4uiv)
+#define glUniformBlockBinding GLES2_GET_FUN(UniformBlockBinding)
 #define glUniformMatrix2fv GLES2_GET_FUN(UniformMatrix2fv)
 #define glUniformMatrix2x3fv GLES2_GET_FUN(UniformMatrix2x3fv)
 #define glUniformMatrix2x4fv GLES2_GET_FUN(UniformMatrix2x4fv)
@@ -258,6 +263,9 @@
   GLES2_GET_FUN(RateLimitOffscreenContextCHROMIUM)
 #define glGetProgramInfoCHROMIUM GLES2_GET_FUN(GetProgramInfoCHROMIUM)
 #define glGetUniformBlocksCHROMIUM GLES2_GET_FUN(GetUniformBlocksCHROMIUM)
+#define glGetTransformFeedbackVaryingsCHROMIUM \
+  GLES2_GET_FUN(GetTransformFeedbackVaryingsCHROMIUM)
+#define glGetUniformsES3CHROMIUM GLES2_GET_FUN(GetUniformsES3CHROMIUM)
 #define glCreateStreamTextureCHROMIUM GLES2_GET_FUN(CreateStreamTextureCHROMIUM)
 #define glCreateImageCHROMIUM GLES2_GET_FUN(CreateImageCHROMIUM)
 #define glDestroyImageCHROMIUM GLES2_GET_FUN(DestroyImageCHROMIUM)
diff --git a/gpu/blink/webgraphicscontext3d_impl.cc b/gpu/blink/webgraphicscontext3d_impl.cc
index 2681abc..4f728cf 100644
--- a/gpu/blink/webgraphicscontext3d_impl.cc
+++ b/gpu/blink/webgraphicscontext3d_impl.cc
@@ -148,6 +148,22 @@
   return gl_->glname(a1, a2, a3, a4, a5, a6, a7, a8, a9);               \
 }
 
+#define DELEGATE_TO_GL_10(name, glname, t1, t2, t3, t4, t5, t6, t7, t8, \
+                          t9, t10)                                      \
+void WebGraphicsContext3DImpl::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5,  \
+                                    t6 a6, t7 a7, t8 a8, t9 a9,         \
+                                    t10 a10) {                          \
+  gl_->glname(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);                 \
+}
+
+#define DELEGATE_TO_GL_11(name, glname, t1, t2, t3, t4, t5, t6, t7, t8, \
+                          t9, t10, t11)                                 \
+void WebGraphicsContext3DImpl::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5,  \
+                                    t6 a6, t7 a7, t8 a8, t9 a9, t10 a10,\
+                                    t11 a11) {                          \
+  gl_->glname(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);            \
+}
+
 WebGraphicsContext3DImpl::WebGraphicsContext3DImpl()
     : initialized_(false),
       initialize_failed_(false),
@@ -709,23 +725,6 @@
 DELEGATE_TO_GL_4(viewport, Viewport,
                  WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei)
 
-DELEGATE_TO_GL_2(genBuffers, GenBuffers, WGC3Dsizei, WebGLId*);
-
-DELEGATE_TO_GL_2(genFramebuffers, GenFramebuffers, WGC3Dsizei, WebGLId*);
-
-DELEGATE_TO_GL_2(genRenderbuffers, GenRenderbuffers, WGC3Dsizei, WebGLId*);
-
-DELEGATE_TO_GL_2(genTextures, GenTextures, WGC3Dsizei, WebGLId*);
-
-DELEGATE_TO_GL_2(deleteBuffers, DeleteBuffers, WGC3Dsizei, WebGLId*);
-
-DELEGATE_TO_GL_2(deleteFramebuffers, DeleteFramebuffers, WGC3Dsizei, WebGLId*);
-
-DELEGATE_TO_GL_2(deleteRenderbuffers, DeleteRenderbuffers, WGC3Dsizei,
-                 WebGLId*);
-
-DELEGATE_TO_GL_2(deleteTextures, DeleteTextures, WGC3Dsizei, WebGLId*);
-
 WebGLId WebGraphicsContext3DImpl::createBuffer() {
   GLuint o;
   gl_->GenBuffers(1, &o);
@@ -974,6 +973,160 @@
                  RenderbufferStorageMultisampleEXT, WGC3Denum, WGC3Dsizei,
                  WGC3Denum, WGC3Dsizei, WGC3Dsizei)
 
+DELEGATE_TO_GL_1(beginTransformFeedback, BeginTransformFeedback, WGC3Denum)
+DELEGATE_TO_GL_3(bindBufferBase, BindBufferBase, WGC3Denum, WGC3Duint,
+                 WGC3Duint)
+DELEGATE_TO_GL_5(bindBufferRange, BindBufferRange, WGC3Denum, WGC3Duint,
+                 WGC3Duint, WGC3Dintptr, WGC3Dsizeiptr)
+DELEGATE_TO_GL_2(bindSampler, BindSampler, WGC3Duint, WebGLId)
+DELEGATE_TO_GL_2(bindTransformFeedback, BindTransformFeedback, WGC3Denum,
+                 WebGLId)
+DELEGATE_TO_GL_4(clearBufferfi, ClearBufferfi, WGC3Denum, WGC3Dint, WGC3Dfloat,
+                 WGC3Dint)
+DELEGATE_TO_GL_3(clearBufferfv, ClearBufferfv, WGC3Denum, WGC3Dint,
+                 const WGC3Dfloat *)
+DELEGATE_TO_GL_3(clearBufferiv, ClearBufferiv, WGC3Denum, WGC3Dint,
+                 const WGC3Dint *)
+DELEGATE_TO_GL_3(clearBufferuiv, ClearBufferuiv, WGC3Denum, WGC3Dint,
+                 const WGC3Duint *)
+//DELEGATE_TO_GL_3R(clientWaitSync, ClientWaitSync, WebGLId, WGC3Dbitfield,
+//                  WGC3Duint64, WGC3Denum)
+//DELEGATE_TO_GL_9(compressedTexImage3D, CompressedTexImage3D, WGC3Denum,
+//                 WGC3Dint, WGC3Denum, WGC3Dsizei, WGC3Dsizei, WGC3Dsizei,
+//                 WGC3Dint, WGC3Dsizei, const void *)
+//DELEGATE_TO_GL_11(compressedTexSubImage3D, CompressedTexSubImage3D, WGC3Denum,
+//                  WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dsizei,
+//                  WGC3Dsizei, WGC3Dsizei, WGC3Denum, WGC3Dsizei, const void *)
+DELEGATE_TO_GL_5(copyBufferSubData, CopyBufferSubData, WGC3Denum, WGC3Denum,
+                 WGC3Dintptr, WGC3Dintptr, WGC3Dsizeiptr)
+DELEGATE_TO_GL_9(copyTexSubImage3D, CopyTexSubImage3D, WGC3Denum, WGC3Dint,
+                 WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dint, WGC3Dsizei,
+                 WGC3Dsizei)
+WebGLId WebGraphicsContext3DImpl::createSampler() {
+  GLuint sampler;
+  gl_->GenSamplers(1, &sampler);
+  return sampler;
+}
+WebGLId WebGraphicsContext3DImpl::createTransformFeedback() {
+  GLuint tf;
+  gl_->GenTransformFeedbacks(1, &tf);
+  return tf;
+}
+void WebGraphicsContext3DImpl::deleteSampler(WebGLId sampler) {
+  gl_->DeleteSamplers(1, &sampler);
+}
+//DELEGATE_TO_GL_1(deleteSync, DeleteSync, WebGLId)
+void WebGraphicsContext3DImpl::deleteTransformFeedback(WebGLId tf) {
+  gl_->DeleteTransformFeedbacks(1, &tf);
+}
+DELEGATE_TO_GL(endTransformFeedback, EndTransformFeedback)
+//DELEGATE_TO_GL_2R(fenceSync, FenceSync, WGC3Denum, WGC3Dbitfield, WebGLId)
+DELEGATE_TO_GL_5(framebufferTextureLayer, FramebufferTextureLayer, WGC3Denum,
+                 WGC3Denum, WGC3Duint, WGC3Dint, WGC3Dint)
+DELEGATE_TO_GL_5(getActiveUniformBlockName, GetActiveUniformBlockName,
+                 WGC3Duint, WGC3Duint, WGC3Dsizei, WGC3Dsizei *, WGC3Dchar *)
+DELEGATE_TO_GL_4(getActiveUniformBlockiv, GetActiveUniformBlockiv, WGC3Duint,
+                 WGC3Duint, WGC3Denum, WGC3Dint *)
+//DELEGATE_TO_GL_5(getActiveUniformsiv, GetActiveUniformsiv, WGC3Duint,
+//                 WGC3Dsizei, const WGC3Duint *, WGC3Denum, WGC3Dint *)
+DELEGATE_TO_GL_2R(getFragDataLocation, GetFragDataLocation, WGC3Duint,
+                  const WGC3Dchar *, WGC3Dint)
+DELEGATE_TO_GL_5(getInternalformativ, GetInternalformativ, WGC3Denum, WGC3Denum,
+                 WGC3Denum, WGC3Dsizei, WGC3Dint *)
+DELEGATE_TO_GL_3(getSamplerParameterfv, GetSamplerParameterfv, WGC3Duint,
+                 WGC3Denum, WGC3Dfloat *)
+DELEGATE_TO_GL_3(getSamplerParameteriv, GetSamplerParameteriv, WGC3Duint,
+                 WGC3Denum, WGC3Dint *)
+//DELEGATE_TO_GL_7(getTransformFeedbackVarying, GetTransformFeedbackVarying,
+//                 WGC3Duint, WGC3Duint, WGC3Dsizei, WGC3Dsizei *, WGC3Dsizei *,
+//                 WGC3Denum *, WGC3Dchar *)
+DELEGATE_TO_GL_2R(getUniformBlockIndex, GetUniformBlockIndex, WGC3Duint,
+                  const WGC3Dchar *, WGC3Duint)
+//DELEGATE_TO_GL_4(getUniformIndices, GetUniformIndices, WGC3Duint, WGC3Dsizei,
+//                 const WGC3Dchar *const*, WGC3Duint *)
+//DELEGATE_TO_GL_3(getUniformuiv, GetUniformuiv, WGC3Duint, WGC3Dint,
+//                 WGC3Duint *)
+//DELEGATE_TO_GL_3(getVertexAttribIiv, GetVertexAttribIiv, WGC3Duint,
+//                 WGC3Denum, WGC3Dint *)
+//DELEGATE_TO_GL_3(getVertexAttribIuiv, GetVertexAttribIuiv, WGC3Duint,
+//                 WGC3Denum, WGC3Duint *)
+DELEGATE_TO_GL_3(invalidateFramebuffer, InvalidateFramebuffer, WGC3Denum,
+                 WGC3Dsizei, const WGC3Denum *)
+DELEGATE_TO_GL_7(invalidateSubFramebuffer, InvalidateSubFramebuffer, WGC3Denum,
+                 WGC3Dsizei, const WGC3Denum *, WGC3Dint, WGC3Dint, WGC3Dsizei,
+                 WGC3Dsizei)
+DELEGATE_TO_GL_1R(isSampler, IsSampler, WebGLId, WGC3Dboolean)
+//DELEGATE_TO_GL_1R(isSync, IsSync, WebGLId, WGC3Dboolean)
+DELEGATE_TO_GL_1R(isTransformFeedback, IsTransformFeedback, WGC3Duint,
+                  WGC3Dboolean)
+DELEGATE_TO_GL(pauseTransformFeedback, PauseTransformFeedback)
+//DELEGATE_TO_GL_3(programParameteri, ProgramParameteri, WGC3Duint, WGC3Denum,
+//                 WGC3Dint)
+DELEGATE_TO_GL_1(readBuffer, ReadBuffer, WGC3Denum)
+DELEGATE_TO_GL(resumeTransformFeedback, ResumeTransformFeedback)
+DELEGATE_TO_GL_3(samplerParameterf, SamplerParameterf, WGC3Duint, WGC3Denum,
+                 WGC3Dfloat)
+DELEGATE_TO_GL_3(samplerParameterfv, SamplerParameterfv, WGC3Duint, WGC3Denum,
+                 const WGC3Dfloat *)
+DELEGATE_TO_GL_3(samplerParameteri, SamplerParameteri, WGC3Duint, WGC3Denum,
+                 WGC3Dint)
+DELEGATE_TO_GL_3(samplerParameteriv, SamplerParameteriv, WGC3Duint, WGC3Denum,
+                 const WGC3Dint *)
+DELEGATE_TO_GL_10(texImage3D, TexImage3D, WGC3Denum, WGC3Dint, WGC3Dint,
+                  WGC3Dsizei, WGC3Dsizei, WGC3Dsizei, WGC3Dint, WGC3Denum,
+                  WGC3Denum, const void *)
+DELEGATE_TO_GL_6(texStorage3D, TexStorage3D, WGC3Denum, WGC3Dsizei, WGC3Denum,
+                 WGC3Dsizei, WGC3Dsizei, WGC3Dsizei)
+DELEGATE_TO_GL_11(texSubImage3D, TexSubImage3D, WGC3Denum, WGC3Dint, WGC3Dint,
+                  WGC3Dint, WGC3Dint, WGC3Dsizei, WGC3Dsizei, WGC3Dsizei,
+                  WGC3Denum, WGC3Denum, const void *)
+DELEGATE_TO_GL_4(transformFeedbackVaryings, TransformFeedbackVaryings,
+                 WGC3Duint, WGC3Dsizei, const WGC3Dchar *const*, WGC3Denum)
+DELEGATE_TO_GL_2(uniform1ui, Uniform1ui, WGC3Dint, WGC3Duint)
+DELEGATE_TO_GL_3(uniform1uiv, Uniform1uiv, WGC3Dint, WGC3Dsizei,
+                 const WGC3Duint *)
+DELEGATE_TO_GL_3(uniform2ui, Uniform2ui, WGC3Dint, WGC3Duint, WGC3Duint)
+DELEGATE_TO_GL_3(uniform2uiv, Uniform2uiv, WGC3Dint, WGC3Dsizei,
+                 const WGC3Duint *)
+DELEGATE_TO_GL_4(uniform3ui, Uniform3ui, WGC3Dint, WGC3Duint, WGC3Duint,
+                 WGC3Duint)
+DELEGATE_TO_GL_3(uniform3uiv, Uniform3uiv, WGC3Dint, WGC3Dsizei,
+                 const WGC3Duint *)
+DELEGATE_TO_GL_5(uniform4ui, Uniform4ui, WGC3Dint, WGC3Duint, WGC3Duint,
+                 WGC3Duint, WGC3Duint)
+DELEGATE_TO_GL_3(uniform4uiv, Uniform4uiv, WGC3Dint, WGC3Dsizei,
+                 const WGC3Duint *)
+DELEGATE_TO_GL_3(uniformBlockBinding, UniformBlockBinding, WGC3Duint, WGC3Duint,
+                 WGC3Duint)
+DELEGATE_TO_GL_4(uniformMatrix2x3fv, UniformMatrix2x3fv, WGC3Dint, WGC3Dsizei,
+                 WGC3Dboolean, const WGC3Dfloat*)
+DELEGATE_TO_GL_4(uniformMatrix2x4fv, UniformMatrix2x4fv, WGC3Dint, WGC3Dsizei,
+                 WGC3Dboolean, const WGC3Dfloat*)
+DELEGATE_TO_GL_4(uniformMatrix3x2fv, UniformMatrix3x2fv, WGC3Dint, WGC3Dsizei,
+                 WGC3Dboolean, const WGC3Dfloat*)
+DELEGATE_TO_GL_4(uniformMatrix3x4fv, UniformMatrix3x4fv, WGC3Dint, WGC3Dsizei,
+                 WGC3Dboolean, const WGC3Dfloat*)
+DELEGATE_TO_GL_4(uniformMatrix4x2fv, UniformMatrix4x2fv, WGC3Dint, WGC3Dsizei,
+                 WGC3Dboolean, const WGC3Dfloat*)
+DELEGATE_TO_GL_4(uniformMatrix4x3fv, UniformMatrix4x3fv, WGC3Dint, WGC3Dsizei,
+                 WGC3Dboolean, const WGC3Dfloat*)
+DELEGATE_TO_GL_5(vertexAttribI4i, VertexAttribI4i, WGC3Duint, WGC3Dint,
+                 WGC3Dint, WGC3Dint, WGC3Dint)
+DELEGATE_TO_GL_2(vertexAttribI4iv, VertexAttribI4iv, WGC3Duint,
+                 const WGC3Dint *)
+DELEGATE_TO_GL_5(vertexAttribI4ui, VertexAttribI4ui, WGC3Duint, WGC3Duint,
+                 WGC3Duint, WGC3Duint, WGC3Duint)
+DELEGATE_TO_GL_2(vertexAttribI4uiv, VertexAttribI4uiv, WGC3Duint,
+                 const WGC3Duint *)
+void WebGraphicsContext3DImpl::vertexAttribIPointer(
+    WGC3Duint index, WGC3Dint size, WGC3Denum type, WGC3Dsizei stride,
+    WGC3Dintptr offset) {
+  gl_->VertexAttribIPointer(
+      index, size, type, stride,
+      reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
+}
+//DELEGATE_TO_GL_3(waitSync, WaitSync, WebGLId, WGC3Dbitfield, WGC3Duint64)
+
 GrGLInterface* WebGraphicsContext3DImpl::createGrGLInterface() {
   return skia_bindings::CreateCommandBufferSkiaGLBinding();
 }
diff --git a/gpu/blink/webgraphicscontext3d_impl.h b/gpu/blink/webgraphicscontext3d_impl.h
index 11a3dc5..ff2ca97 100644
--- a/gpu/blink/webgraphicscontext3d_impl.h
+++ b/gpu/blink/webgraphicscontext3d_impl.h
@@ -37,6 +37,7 @@
 using blink::WGC3Dclampf;
 using blink::WGC3Dintptr;
 using blink::WGC3Dsizeiptr;
+using blink::WGC3Duint64;
 
 namespace gpu_blink {
 
@@ -371,17 +372,6 @@
   virtual void viewport(WGC3Dint x, WGC3Dint y,
                         WGC3Dsizei width, WGC3Dsizei height);
 
-  // Support for buffer creation and deletion
-  virtual void genBuffers(WGC3Dsizei count, WebGLId* ids);
-  virtual void genFramebuffers(WGC3Dsizei count, WebGLId* ids);
-  virtual void genRenderbuffers(WGC3Dsizei count, WebGLId* ids);
-  virtual void genTextures(WGC3Dsizei count, WebGLId* ids);
-
-  virtual void deleteBuffers(WGC3Dsizei count, WebGLId* ids);
-  virtual void deleteFramebuffers(WGC3Dsizei count, WebGLId* ids);
-  virtual void deleteRenderbuffers(WGC3Dsizei count, WebGLId* ids);
-  virtual void deleteTextures(WGC3Dsizei count, WebGLId* ids);
-
   virtual WebGLId createBuffer();
   virtual WebGLId createFramebuffer();
   virtual WebGLId createRenderbuffer();
@@ -566,6 +556,147 @@
       WGC3Denum target, WGC3Dsizei samples, WGC3Denum internalformat,
       WGC3Dsizei width, WGC3Dsizei height);
 
+  // OpenGL ES 3.0 functions not represented by pre-existing extensions
+  virtual void beginTransformFeedback(WGC3Denum primitiveMode);
+  virtual void bindBufferBase(WGC3Denum target, WGC3Duint index,
+      WGC3Duint buffer);
+  virtual void bindBufferRange(WGC3Denum target, WGC3Duint index,
+      WGC3Duint buffer, WGC3Dintptr offset, WGC3Dsizeiptr size);
+  virtual void bindSampler(WGC3Duint unit, WebGLId sampler);
+  virtual void bindTransformFeedback(WGC3Denum target,
+      WebGLId transformfeedback);
+  virtual void clearBufferfi(WGC3Denum buffer, WGC3Dint drawbuffer,
+      WGC3Dfloat depth, WGC3Dint stencil);
+  virtual void clearBufferfv(WGC3Denum buffer, WGC3Dint drawbuffer,
+      const WGC3Dfloat *value);
+  virtual void clearBufferiv(WGC3Denum buffer, WGC3Dint drawbuffer,
+      const WGC3Dint *value);
+  virtual void clearBufferuiv(WGC3Denum buffer, WGC3Dint drawbuffer,
+      const WGC3Duint *value);
+  //virtual WGC3Denum clientWaitSync(WebGLId sync, WGC3Dbitfield flags,
+  //    WGC3Duint64 timeout);
+  //virtual void compressedTexImage3D(WGC3Denum target, WGC3Dint level,
+  //    WGC3Denum internalformat, WGC3Dsizei width, WGC3Dsizei height,
+  //    WGC3Dsizei depth, WGC3Dint border, WGC3Dsizei imageSize,
+  //    const void *data);
+  //virtual void compressedTexSubImage3D(WGC3Denum target, WGC3Dint level,
+  //    WGC3Dint xoffset, WGC3Dint yoffset, WGC3Dint zoffset, WGC3Dsizei width,
+  //    WGC3Dsizei height, WGC3Dsizei depth, WGC3Denum format,
+  //    WGC3Dsizei imageSize, const void *data);
+  virtual void copyBufferSubData(WGC3Denum readTarget, WGC3Denum writeTarget,
+      WGC3Dintptr readOffset, WGC3Dintptr writeOffset, WGC3Dsizeiptr size);
+  virtual void copyTexSubImage3D(WGC3Denum target, WGC3Dint level,
+      WGC3Dint xoffset, WGC3Dint yoffset, WGC3Dint zoffset, WGC3Dint x,
+      WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height);
+  virtual WebGLId createSampler();
+  virtual WebGLId createTransformFeedback();
+  virtual void deleteSampler(WebGLId sampler);
+  //virtual void deleteSync(WebGLId sync);
+  virtual void deleteTransformFeedback(WebGLId transformfeedback);
+  virtual void endTransformFeedback(void);
+  //virtual WebGLId fenceSync(WGC3Denum condition, WGC3Dbitfield flags);
+  virtual void framebufferTextureLayer(WGC3Denum target, WGC3Denum attachment,
+      WGC3Duint texture, WGC3Dint level, WGC3Dint layer);
+  virtual void getActiveUniformBlockName(WGC3Duint program,
+      WGC3Duint uniformBlockIndex, WGC3Dsizei bufSize, WGC3Dsizei *length,
+      WGC3Dchar *uniformBlockName);
+  virtual void getActiveUniformBlockiv(WGC3Duint program,
+      WGC3Duint uniformBlockIndex, WGC3Denum pname, WGC3Dint *params);
+  //virtual void getActiveUniformsiv(WGC3Duint program, WGC3Dsizei uniformCount,
+  //    const WGC3Duint *uniformIndices, WGC3Denum pname, WGC3Dint *params);
+  virtual WGC3Dint getFragDataLocation(WGC3Duint program,
+      const WGC3Dchar *name);
+  virtual void getInternalformativ(WGC3Denum target, WGC3Denum internalformat,
+      WGC3Denum pname, WGC3Dsizei bufSize, WGC3Dint *params);
+  virtual void getSamplerParameterfv(WGC3Duint sampler, WGC3Denum pname,
+      WGC3Dfloat *params);
+  virtual void getSamplerParameteriv(WGC3Duint sampler, WGC3Denum pname,
+      WGC3Dint *params);
+  //virtual void getTransformFeedbackVarying(WGC3Duint program, WGC3Duint index,
+  //    WGC3Dsizei bufSize, WGC3Dsizei *length, WGC3Dsizei *size,
+  //    WGC3Denum *type, WGC3Dchar *name);
+  virtual WGC3Duint getUniformBlockIndex(WGC3Duint program,
+      const WGC3Dchar *uniformBlockName);
+  //virtual void getUniformIndices(WGC3Duint program, WGC3Dsizei uniformCount,
+  //    const WGC3Dchar *const*uniformNames, WGC3Duint *uniformIndices);
+  //virtual void getUniformuiv(WGC3Duint program, WGC3Dint location,
+  //    WGC3Duint *params);
+  //virtual void getVertexAttribIiv(WGC3Duint index, WGC3Denum pname,
+  //    WGC3Dint *params);
+  //virtual void getVertexAttribIuiv(WGC3Duint index, WGC3Denum pname,
+  //    WGC3Duint *params);
+  virtual void invalidateFramebuffer(WGC3Denum target,
+      WGC3Dsizei numAttachments, const WGC3Denum *attachments);
+  virtual void invalidateSubFramebuffer(WGC3Denum target,
+      WGC3Dsizei numAttachments, const WGC3Denum *attachments, WGC3Dint x,
+      WGC3Dint y, WGC3Dsizei width, WGC3Dsizei height);
+  virtual WGC3Dboolean isSampler(WebGLId sampler);
+  //virtual WGC3Dboolean isSync(WebGLId sync);
+  virtual WGC3Dboolean isTransformFeedback(WGC3Duint id);
+  virtual void pauseTransformFeedback(void);
+  //virtual void programParameteri(WGC3Duint program, WGC3Denum pname,
+  //    WGC3Dint value);
+  virtual void readBuffer(WGC3Denum src);
+  virtual void resumeTransformFeedback(void);
+  virtual void samplerParameterf(WGC3Duint sampler, WGC3Denum pname,
+      WGC3Dfloat param);
+  virtual void samplerParameterfv(WGC3Duint sampler, WGC3Denum pname,
+      const WGC3Dfloat *param);
+  virtual void samplerParameteri(WGC3Duint sampler, WGC3Denum pname,
+      WGC3Dint param);
+  virtual void samplerParameteriv(WGC3Duint sampler, WGC3Denum pname,
+      const WGC3Dint *param);
+  virtual void texImage3D(WGC3Denum target, WGC3Dint level,
+      WGC3Dint internalformat, WGC3Dsizei width, WGC3Dsizei height,
+      WGC3Dsizei depth, WGC3Dint border, WGC3Denum format, WGC3Denum type,
+      const void *pixels);
+  virtual void texStorage3D(WGC3Denum target, WGC3Dsizei levels,
+      WGC3Denum internalformat, WGC3Dsizei width, WGC3Dsizei height,
+      WGC3Dsizei depth);
+  virtual void texSubImage3D(WGC3Denum target, WGC3Dint level, WGC3Dint xoffset,
+      WGC3Dint yoffset, WGC3Dint zoffset, WGC3Dsizei width, WGC3Dsizei height,
+      WGC3Dsizei depth, WGC3Denum format, WGC3Denum type, const void *pixels);
+  virtual void transformFeedbackVaryings(WGC3Duint program, WGC3Dsizei count,
+      const WGC3Dchar *const*varyings, WGC3Denum bufferMode);
+  virtual void uniform1ui(WGC3Dint location, WGC3Duint x);
+  virtual void uniform1uiv(WGC3Dint location, WGC3Dsizei count,
+      const WGC3Duint *value);
+  virtual void uniform2ui(WGC3Dint location, WGC3Duint x, WGC3Duint y);
+  virtual void uniform2uiv(WGC3Dint location, WGC3Dsizei count,
+      const WGC3Duint *value);
+  virtual void uniform3ui(WGC3Dint location, WGC3Duint x, WGC3Duint y,
+      WGC3Duint z);
+  virtual void uniform3uiv(WGC3Dint location, WGC3Dsizei count,
+      const WGC3Duint *value);
+  virtual void uniform4ui(WGC3Dint location, WGC3Duint x, WGC3Duint y,
+      WGC3Duint z, WGC3Duint w);
+  virtual void uniform4uiv(WGC3Dint location, WGC3Dsizei count,
+      const WGC3Duint *value);
+  virtual void uniformBlockBinding(WGC3Duint program,
+      WGC3Duint uniformBlockIndex, WGC3Duint uniformBlockBinding);
+  virtual void uniformMatrix2x3fv(WGC3Dint location, WGC3Dsizei count,
+      WGC3Dboolean transpose, const WGC3Dfloat* value);
+  virtual void uniformMatrix2x4fv(WGC3Dint location, WGC3Dsizei count,
+      WGC3Dboolean transpose, const WGC3Dfloat* value);
+  virtual void uniformMatrix3x2fv(WGC3Dint location, WGC3Dsizei count,
+      WGC3Dboolean transpose, const WGC3Dfloat* value);
+  virtual void uniformMatrix3x4fv(WGC3Dint location, WGC3Dsizei count,
+      WGC3Dboolean transpose, const WGC3Dfloat* value);
+  virtual void uniformMatrix4x2fv(WGC3Dint location, WGC3Dsizei count,
+      WGC3Dboolean transpose, const WGC3Dfloat* value);
+  virtual void uniformMatrix4x3fv(WGC3Dint location, WGC3Dsizei count,
+      WGC3Dboolean transpose, const WGC3Dfloat* value);
+  virtual void vertexAttribI4i(WGC3Duint index, WGC3Dint x, WGC3Dint y,
+      WGC3Dint z, WGC3Dint w);
+  virtual void vertexAttribI4iv(WGC3Duint index, const WGC3Dint *v);
+  virtual void vertexAttribI4ui(WGC3Duint index, WGC3Duint x, WGC3Duint y,
+      WGC3Duint z, WGC3Duint w);
+  virtual void vertexAttribI4uiv(WGC3Duint index, const WGC3Duint *v);
+  virtual void vertexAttribIPointer(WGC3Duint index, WGC3Dint size,
+      WGC3Denum type, WGC3Dsizei stride, WGC3Dintptr pointer);
+  //virtual void waitSync(WebGLId sync, WGC3Dbitfield flags,
+  //    WGC3Duint64 timeout);
+
   virtual GrGLInterface* createGrGLInterface();
 
   ::gpu::gles2::GLES2Interface* GetGLInterface() {
diff --git a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
index 386d349..ff83e5a 100644
--- a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
+++ b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -153,6 +153,10 @@
   return context_ && !isContextLost();
 }
 
+void WebGraphicsContext3DInProcessCommandBufferImpl::SetLock(base::Lock* lock) {
+  context_->SetLock(lock);
+}
+
 bool WebGraphicsContext3DInProcessCommandBufferImpl::isContextLost() {
   return context_lost_reason_ != GL_NO_ERROR;
 }
diff --git a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h
index 94816a8..8aba802 100644
--- a/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h
+++ b/gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h
@@ -57,6 +57,7 @@
   size_t GetMappedMemoryLimit();
 
   bool InitializeOnCurrentThread();
+  void SetLock(base::Lock* lock);
 
   //----------------------------------------------------------------------
   // WebGraphicsContext3D methods
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index dc576d7..ca39150 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1313,6 +1313,37 @@
       'GL_MOUSE_POSITION_CHROMIUM',
     ],
   },
+  'UniformParameter': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_UNIFORM_SIZE',
+      'GL_UNIFORM_TYPE',
+      'GL_UNIFORM_NAME_LENGTH',
+      'GL_UNIFORM_BLOCK_INDEX',
+      'GL_UNIFORM_OFFSET',
+      'GL_UNIFORM_ARRAY_STRIDE',
+      'GL_UNIFORM_MATRIX_STRIDE',
+      'GL_UNIFORM_IS_ROW_MAJOR',
+    ],
+    'invalid': [
+      'GL_UNIFORM_BLOCK_NAME_LENGTH',
+    ],
+  },
+  'UniformBlockParameter': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_UNIFORM_BLOCK_BINDING',
+      'GL_UNIFORM_BLOCK_DATA_SIZE',
+      'GL_UNIFORM_BLOCK_NAME_LENGTH',
+      'GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS',
+      'GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES',
+      'GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER',
+      'GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER',
+    ],
+    'invalid': [
+      'GL_NEAREST',
+    ],
+  },
   'VertexAttribType': {
     'type': 'GLenum',
     'valid': [
@@ -2034,6 +2065,12 @@
       'uint32_t type',
     ],
   },
+  'GetActiveUniformBlockiv': {
+    'type': 'Custom',
+    'data_transfer_methods': ['shm'],
+    'result': ['SizedResult<GLint>'],
+    'unsafe': True,
+  },
   'GetActiveUniformBlockName': {
     'type': 'Custom',
     'data_transfer_methods': ['shm'],
@@ -2043,6 +2080,15 @@
     'result': ['int32_t'],
     'unsafe': True,
   },
+  'GetActiveUniformsiv': {
+    'type': 'Custom',
+    'data_transfer_methods': ['shm'],
+    'cmd_args':
+        'GLidProgram program, uint32_t indices_bucket_id, GLenum pname, '
+        'GLint* params',
+    'result': ['SizedResult<GLint>'],
+    'unsafe': True,
+  },
   'GetAttachedShaders': {
     'type': 'Custom',
     'data_transfer_methods': ['shm'],
@@ -2234,6 +2280,41 @@
     'result': ['uint32_t'],
     'unsafe': True,
   },
+  'GetUniformsES3CHROMIUM': {
+    'type': 'Custom',
+    'expectation': False,
+    'impl_func': False,
+    'extension': True,
+    'chromium': True,
+    'client_test': False,
+    'cmd_args': 'GLidProgram program, uint32_t bucket_id',
+    'result': ['uint32_t'],
+    'unsafe': True,
+  },
+  'GetTransformFeedbackVarying': {
+    'type': 'Custom',
+    'data_transfer_methods': ['shm'],
+    'cmd_args':
+        'GLidProgram program, GLuint index, uint32_t name_bucket_id, '
+        'void* result',
+    'result': [
+      'int32_t success',
+      'int32_t size',
+      'uint32_t type',
+    ],
+    'unsafe': True,
+  },
+  'GetTransformFeedbackVaryingsCHROMIUM': {
+    'type': 'Custom',
+    'expectation': False,
+    'impl_func': False,
+    'extension': True,
+    'chromium': True,
+    'client_test': False,
+    'cmd_args': 'GLidProgram program, uint32_t bucket_id',
+    'result': ['uint32_t'],
+    'unsafe': True,
+  },
   'GetUniformfv': {
     'type': 'Custom',
     'data_transfer_methods': ['shm'],
@@ -2244,6 +2325,14 @@
     'data_transfer_methods': ['shm'],
     'result': ['SizedResult<GLint>'],
   },
+  'GetUniformIndices': {
+    'type': 'Custom',
+    'data_transfer_methods': ['shm'],
+    'result': ['SizedResult<GLuint>'],
+    'cmd_args': 'GLidProgram program, uint32_t names_bucket_id, '
+                'GLuint* indices',
+    'unsafe': True,
+  },
   'GetUniformLocation': {
     'type': 'Custom',
     'data_transfer_methods': ['shm'],
@@ -2735,6 +2824,11 @@
     'count': 12,
     'unsafe': True,
   },
+  'UniformBlockBinding': {
+    'type': 'Custom',
+    'impl_func': False,
+    'unsafe': True,
+  },
   'UnmapBufferCHROMIUM': {
     'gen_cmd': False,
     'extension': True,
@@ -6480,90 +6574,7 @@
       })
     for arg in func.GetOriginalArgs():
       arg.WriteClientSideValidationCode(file, func)
-    size_code_block = """  // Compute the total size.
-  base::CheckedNumeric<size_t> total_size = count;
-  total_size += 1;
-  total_size *= sizeof(GLint);
-  if (!total_size.IsValid()) {
-    SetGLError(GL_INVALID_VALUE, "gl%(func_name)s", "overflow");
-    return;
-  }
-  size_t header_size = total_size.ValueOrDefault(0);
-  std::vector<GLint> header(count + 1);
-  header[0] = static_cast<GLint>(count);
-  for (GLsizei ii = 0; ii < count; ++ii) {
-    GLint len = 0;
-    if (%(data)s[ii]) {"""
-    if length_arg == None:
-      size_code_block += """
-      len = static_cast<GLint>(strlen(%(data)s[ii]));"""
-    else:
-      size_code_block += """
-      len = (%(length)s && %(length)s[ii] >= 0) ?
-          %(length)s[ii] : base::checked_cast<GLint>(strlen(%(data)s[ii]));"""
-    size_code_block += """
-    }
-    total_size += len;
-    total_size += 1;  // NULL at the end of each char array.
-    if (!total_size.IsValid()) {
-      SetGLError(GL_INVALID_VALUE, "gl%(func_name)s", "overflow");
-      return;
-    }
-    header[ii + 1] = len;
-}
-"""
-    file.Write(size_code_block % {
-        'data': data_arg.name,
-        'length': length_arg.name if not length_arg == None else '',
-        'func_name': func.name,
-      })
-    data_code_block = """  // Pack data into a bucket on the service.
-  helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
-  size_t offset = 0;
-  for (GLsizei ii = 0; ii <= count; ++ii) {
-    const char* src = (ii == 0) ? reinterpret_cast<const char*>(&header[0]) :
-        %(data)s[ii - 1];
-    base::CheckedNumeric<size_t> checked_size = (ii == 0) ? header_size :
-        static_cast<size_t>(header[ii]);
-    if (ii > 0) {
-      checked_size += 1;  // NULL in the end.
-    }
-    if (!checked_size.IsValid()) {
-      SetGLError(GL_INVALID_VALUE, "gl%(func_name)s", "overflow");
-      return;
-    }
-    size_t size = checked_size.ValueOrDefault(0);
-    while (size) {
-      ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
-      if (!buffer.valid() || buffer.size() == 0) {
-        SetGLError(GL_OUT_OF_MEMORY, "gl%(func_name)s", "too large");
-        return;
-      }
-      size_t copy_size = buffer.size();
-      if (ii > 0 && buffer.size() == size)
-        --copy_size;
-      if (copy_size)
-        memcpy(buffer.address(), src, copy_size);
-      if (copy_size < buffer.size()) {
-        // Append NULL in the end.
-        DCHECK(copy_size + 1 == buffer.size());
-        char* str = reinterpret_cast<char*>(buffer.address());
-        str[copy_size] = 0;
-      }
-      helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
-                             buffer.shm_id(), buffer.offset());
-      offset += buffer.size();
-      src += buffer.size();
-      size -= buffer.size();
-    }
-  }
-  DCHECK_EQ(total_size.ValueOrDefault(0), offset);
-"""
-    file.Write(data_code_block % {
-        'data': data_arg.name,
-        'length': length_arg.name if not length_arg == None else '',
-        'func_name': func.name,
-      })
+
     bucket_args = []
     for arg in func.GetOriginalArgs():
       if arg.name == 'count' or arg == self.__GetLengthArg(func):
@@ -6572,12 +6583,22 @@
         bucket_args.append('kResultBucketId')
       else:
         bucket_args.append(arg.name)
-    file.Write("  helper_->%sBucket(%s);\n" %
-               (func.name, ", ".join(bucket_args)))
-    file.Write("  helper_->SetBucketSize(kResultBucketId, 0);");
-    file.Write("  CheckGLError();\n")
-    file.Write("}\n")
-    file.Write("\n")
+    code_block = """
+  if (!PackStringsToBucket(count, %(data)s, %(length)s, "gl%(func_name)s")) {
+    return;
+  }
+  helper_->%(func_name)sBucket(%(bucket_args)s);
+  helper_->SetBucketSize(kResultBucketId, 0);
+  CheckGLError();
+}
+
+"""
+    file.Write(code_block % {
+        'data': data_arg.name,
+        'length': length_arg.name if not length_arg == None else 'NULL',
+        'func_name': func.name,
+        'bucket_args': ', '.join(bucket_args),
+      })
 
   def WriteGLES2ImplementationUnitTest(self, func, file):
     """Overrriden from TypeHandler."""
@@ -8009,48 +8030,21 @@
   def WriteGetCode(self, file):
     """Overridden from Argument."""
     code = """
-  const size_t kMinBucketSize = sizeof(GLint);
-  // Each string has at least |length| in the header and a NUL character.
-  const size_t kMinStringSize = sizeof(GLint) + 1;
   Bucket* bucket = GetBucket(c.%(name)s);
   if (!bucket) {
     return error::kInvalidArguments;
   }
-  const size_t bucket_size = bucket->size();
-  if (bucket_size < kMinBucketSize) {
+  GLsizei count = 0;
+  std::vector<char*> strs;
+  std::vector<GLint> len;
+  if (!bucket->GetAsStrings(&count, &strs, &len)) {
     return error::kInvalidArguments;
   }
-  const char* bucket_data = bucket->GetDataAs<const char*>(0, bucket_size);
-  const GLint* header = reinterpret_cast<const GLint*>(bucket_data);
-  GLsizei count = static_cast<GLsizei>(header[0]);
-  if (count < 0) {
-    return error::kInvalidArguments;
-  }
-  const size_t max_count = (bucket_size - kMinBucketSize) / kMinStringSize;
-  if (max_count < static_cast<size_t>(count)) {
-    return error::kInvalidArguments;
-  }
-  const GLint* length = header + 1;
-  scoped_ptr<const char*[]> strs;
-  if (count > 0)
-    strs.reset(new const char*[count]);
-  const char** %(original_name)s = strs.get();
-  base::CheckedNumeric<size_t> total_size = sizeof(GLint);
-  total_size *= count + 1;  // Header size.
-  if (!total_size.IsValid())
-    return error::kInvalidArguments;
-  for (GLsizei ii = 0; ii < count; ++ii) {
-    %(original_name)s[ii] = bucket_data + total_size.ValueOrDefault(0);
-    total_size += length[ii];
-    total_size += 1;  // NUL char at the end of each char array.
-    if (!total_size.IsValid() || total_size.ValueOrDefault(0) > bucket_size ||
-        %(original_name)s[ii][length[ii]] != 0) {
-      return error::kInvalidArguments;
-    }
-  }
-  if (total_size.ValueOrDefault(0) != bucket_size) {
-    return error::kInvalidArguments;
-  }
+  const char** %(original_name)s =
+      strs.size() > 0 ? const_cast<const char**>(&strs[0]) : NULL;
+  const GLint* length =
+      len.size() > 0 ? const_cast<const GLint*>(&len[0]) : NULL;
+  (void)length;
 """
     file.Write(code % {
         'name': self.name,
diff --git a/gpu/command_buffer/client/BUILD.gn b/gpu/command_buffer/client/BUILD.gn
index 04aa039..2d28d1a 100644
--- a/gpu/command_buffer/client/BUILD.gn
+++ b/gpu/command_buffer/client/BUILD.gn
@@ -70,25 +70,25 @@
   "gles2_c_lib.cc",
   "gles2_c_lib_autogen.h",
   "gles2_c_lib_export.h",
-  "gles2_lib.h",
   "gles2_lib.cc",
+  "gles2_lib.h",
 ]
 
 gles2_implementation_source_files = [
   "buffer_tracker.cc",
   "buffer_tracker.h",
-  "client_context_state.h",
   "client_context_state.cc",
+  "client_context_state.h",
   "client_context_state_autogen.h",
   "client_context_state_impl_autogen.h",
   "gles2_impl_export.h",
-  "gles2_implementation_autogen.h",
   "gles2_implementation.cc",
   "gles2_implementation.h",
+  "gles2_implementation_autogen.h",
   "gles2_implementation_impl_autogen.h",
-  "gles2_trace_implementation_autogen.h",
   "gles2_trace_implementation.cc",
   "gles2_trace_implementation.h",
+  "gles2_trace_implementation_autogen.h",
   "gles2_trace_implementation_impl_autogen.h",
   "gpu_switches.cc",
   "gpu_switches.h",
@@ -148,8 +148,8 @@
 
 component("gl_in_process_context") {
   sources = [
-    "gl_in_process_context.h",
     "gl_in_process_context.cc",
+    "gl_in_process_context.h",
     "gl_in_process_context_export.h",
   ]
 
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h
index 111c4f4..46e343d 100644
--- a/gpu/command_buffer/client/client_test_helper.h
+++ b/gpu/command_buffer/client/client_test_helper.h
@@ -110,6 +110,7 @@
   MOCK_METHOD2(SignalQuery, void(uint32 query, const base::Closure& callback));
   MOCK_METHOD1(SetSurfaceVisible, void(bool visible));
   MOCK_METHOD1(CreateStreamTexture, uint32(uint32));
+  MOCK_METHOD1(SetLock, void(base::Lock*));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockClientGpuControl);
diff --git a/gpu/command_buffer/client/gl_in_process_context.cc b/gpu/command_buffer/client/gl_in_process_context.cc
index f10695e..5d8049b 100644
--- a/gpu/command_buffer/client/gl_in_process_context.cc
+++ b/gpu/command_buffer/client/gl_in_process_context.cc
@@ -66,6 +66,7 @@
   void SetContextLostCallback(const base::Closure& callback) override;
   gles2::GLES2Implementation* GetImplementation() override;
   size_t GetMappedMemoryLimit() override;
+  void SetLock(base::Lock* lock) override;
 
 #if defined(OS_ANDROID)
   scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
@@ -85,6 +86,7 @@
   const GLInProcessContextSharedMemoryLimits mem_limits_;
   bool context_lost_;
   base::Closure context_lost_callback_;
+  base::Lock* lock_;
 
   DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl);
 };
@@ -96,7 +98,7 @@
 
 GLInProcessContextImpl::GLInProcessContextImpl(
     const GLInProcessContextSharedMemoryLimits& mem_limits)
-    : mem_limits_(mem_limits), context_lost_(false) {
+    : mem_limits_(mem_limits), context_lost_(false), lock_(nullptr) {
 }
 
 GLInProcessContextImpl::~GLInProcessContextImpl() {
@@ -115,12 +117,20 @@
   return mem_limits_.mapped_memory_reclaim_limit;
 }
 
+void GLInProcessContextImpl::SetLock(base::Lock* lock) {
+  command_buffer_->SetLock(lock);
+  lock_ = lock;
+}
+
 void GLInProcessContextImpl::SetContextLostCallback(
     const base::Closure& callback) {
   context_lost_callback_ = callback;
 }
 
 void GLInProcessContextImpl::OnContextLost() {
+  scoped_ptr<base::AutoLock> lock;
+  if (lock_)
+    lock.reset(new base::AutoLock(*lock_));
   context_lost_ = true;
   if (!context_lost_callback_.is_null()) {
     context_lost_callback_.Run();
diff --git a/gpu/command_buffer/client/gl_in_process_context.h b/gpu/command_buffer/client/gl_in_process_context.h
index ef1820c..8c3a1c5 100644
--- a/gpu/command_buffer/client/gl_in_process_context.h
+++ b/gpu/command_buffer/client/gl_in_process_context.h
@@ -76,6 +76,8 @@
 
   virtual size_t GetMappedMemoryLimit() = 0;
 
+  virtual void SetLock(base::Lock* lock) = 0;
+
 #if defined(OS_ANDROID)
   virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
       uint32 stream_id) = 0;
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index dfe7a6a..23d3d6e 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -338,6 +338,12 @@
   gles2::GetGLContext()->GetActiveUniform(program, index, bufsize, length, size,
                                           type, name);
 }
+void GLES2GetActiveUniformBlockiv(GLuint program,
+                                  GLuint index,
+                                  GLenum pname,
+                                  GLint* params) {
+  gles2::GetGLContext()->GetActiveUniformBlockiv(program, index, pname, params);
+}
 void GLES2GetActiveUniformBlockName(GLuint program,
                                     GLuint index,
                                     GLsizei bufsize,
@@ -346,6 +352,14 @@
   gles2::GetGLContext()->GetActiveUniformBlockName(program, index, bufsize,
                                                    length, name);
 }
+void GLES2GetActiveUniformsiv(GLuint program,
+                              GLsizei count,
+                              const GLuint* indices,
+                              GLenum pname,
+                              GLint* params) {
+  gles2::GetGLContext()->GetActiveUniformsiv(program, count, indices, pname,
+                                             params);
+}
 void GLES2GetAttachedShaders(GLuint program,
                              GLsizei maxcount,
                              GLsizei* count,
@@ -439,6 +453,16 @@
 void GLES2GetTexParameteriv(GLenum target, GLenum pname, GLint* params) {
   gles2::GetGLContext()->GetTexParameteriv(target, pname, params);
 }
+void GLES2GetTransformFeedbackVarying(GLuint program,
+                                      GLuint index,
+                                      GLsizei bufsize,
+                                      GLsizei* length,
+                                      GLsizei* size,
+                                      GLenum* type,
+                                      char* name) {
+  gles2::GetGLContext()->GetTransformFeedbackVarying(program, index, bufsize,
+                                                     length, size, type, name);
+}
 GLuint GLES2GetUniformBlockIndex(GLuint program, const char* name) {
   return gles2::GetGLContext()->GetUniformBlockIndex(program, name);
 }
@@ -448,6 +472,12 @@
 void GLES2GetUniformiv(GLuint program, GLint location, GLint* params) {
   gles2::GetGLContext()->GetUniformiv(program, location, params);
 }
+void GLES2GetUniformIndices(GLuint program,
+                            GLsizei count,
+                            const char* const* names,
+                            GLuint* indices) {
+  gles2::GetGLContext()->GetUniformIndices(program, count, names, indices);
+}
 GLint GLES2GetUniformLocation(GLuint program, const char* name) {
   return gles2::GetGLContext()->GetUniformLocation(program, name);
 }
@@ -773,6 +803,9 @@
 void GLES2Uniform4uiv(GLint location, GLsizei count, const GLuint* v) {
   gles2::GetGLContext()->Uniform4uiv(location, count, v);
 }
+void GLES2UniformBlockBinding(GLuint program, GLuint index, GLuint binding) {
+  gles2::GetGLContext()->UniformBlockBinding(program, index, binding);
+}
 void GLES2UniformMatrix2fv(GLint location,
                            GLsizei count,
                            GLboolean transpose,
@@ -1058,6 +1091,19 @@
                                    void* info) {
   gles2::GetGLContext()->GetUniformBlocksCHROMIUM(program, bufsize, size, info);
 }
+void GLES2GetTransformFeedbackVaryingsCHROMIUM(GLuint program,
+                                               GLsizei bufsize,
+                                               GLsizei* size,
+                                               void* info) {
+  gles2::GetGLContext()->GetTransformFeedbackVaryingsCHROMIUM(program, bufsize,
+                                                              size, info);
+}
+void GLES2GetUniformsES3CHROMIUM(GLuint program,
+                                 GLsizei bufsize,
+                                 GLsizei* size,
+                                 void* info) {
+  gles2::GetGLContext()->GetUniformsES3CHROMIUM(program, bufsize, size, info);
+}
 GLuint GLES2CreateStreamTextureCHROMIUM(GLuint texture) {
   return gles2::GetGLContext()->CreateStreamTextureCHROMIUM(texture);
 }
@@ -1559,10 +1605,18 @@
      reinterpret_cast<GLES2FunctionPointer>(glGetActiveUniform),
     },
     {
+     "glGetActiveUniformBlockiv",
+     reinterpret_cast<GLES2FunctionPointer>(glGetActiveUniformBlockiv),
+    },
+    {
      "glGetActiveUniformBlockName",
      reinterpret_cast<GLES2FunctionPointer>(glGetActiveUniformBlockName),
     },
     {
+     "glGetActiveUniformsiv",
+     reinterpret_cast<GLES2FunctionPointer>(glGetActiveUniformsiv),
+    },
+    {
      "glGetAttachedShaders",
      reinterpret_cast<GLES2FunctionPointer>(glGetAttachedShaders),
     },
@@ -1652,6 +1706,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glGetTexParameteriv),
     },
     {
+     "glGetTransformFeedbackVarying",
+     reinterpret_cast<GLES2FunctionPointer>(glGetTransformFeedbackVarying),
+    },
+    {
      "glGetUniformBlockIndex",
      reinterpret_cast<GLES2FunctionPointer>(glGetUniformBlockIndex),
     },
@@ -1664,6 +1722,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glGetUniformiv),
     },
     {
+     "glGetUniformIndices",
+     reinterpret_cast<GLES2FunctionPointer>(glGetUniformIndices),
+    },
+    {
      "glGetUniformLocation",
      reinterpret_cast<GLES2FunctionPointer>(glGetUniformLocation),
     },
@@ -1976,6 +2038,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glUniform4uiv),
     },
     {
+     "glUniformBlockBinding",
+     reinterpret_cast<GLES2FunctionPointer>(glUniformBlockBinding),
+    },
+    {
      "glUniformMatrix2fv",
      reinterpret_cast<GLES2FunctionPointer>(glUniformMatrix2fv),
     },
@@ -2228,6 +2294,15 @@
      reinterpret_cast<GLES2FunctionPointer>(glGetUniformBlocksCHROMIUM),
     },
     {
+     "glGetTransformFeedbackVaryingsCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(
+         glGetTransformFeedbackVaryingsCHROMIUM),
+    },
+    {
+     "glGetUniformsES3CHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glGetUniformsES3CHROMIUM),
+    },
+    {
      "glCreateStreamTextureCHROMIUM",
      reinterpret_cast<GLES2FunctionPointer>(glCreateStreamTextureCHROMIUM),
     },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index fc0f76d..bda8bb3 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -702,6 +702,18 @@
   }
 }
 
+void GetActiveUniformBlockiv(GLuint program,
+                             GLuint index,
+                             GLenum pname,
+                             uint32_t params_shm_id,
+                             uint32_t params_shm_offset) {
+  gles2::cmds::GetActiveUniformBlockiv* c =
+      GetCmdSpace<gles2::cmds::GetActiveUniformBlockiv>();
+  if (c) {
+    c->Init(program, index, pname, params_shm_id, params_shm_offset);
+  }
+}
+
 void GetActiveUniformBlockName(GLuint program,
                                GLuint index,
                                uint32_t name_bucket_id,
@@ -714,6 +726,19 @@
   }
 }
 
+void GetActiveUniformsiv(GLuint program,
+                         uint32_t indices_bucket_id,
+                         GLenum pname,
+                         uint32_t params_shm_id,
+                         uint32_t params_shm_offset) {
+  gles2::cmds::GetActiveUniformsiv* c =
+      GetCmdSpace<gles2::cmds::GetActiveUniformsiv>();
+  if (c) {
+    c->Init(program, indices_bucket_id, pname, params_shm_id,
+            params_shm_offset);
+  }
+}
+
 void GetAttachedShaders(GLuint program,
                         uint32_t result_shm_id,
                         uint32_t result_shm_offset,
@@ -933,6 +958,18 @@
   }
 }
 
+void GetTransformFeedbackVarying(GLuint program,
+                                 GLuint index,
+                                 uint32_t name_bucket_id,
+                                 uint32_t result_shm_id,
+                                 uint32_t result_shm_offset) {
+  gles2::cmds::GetTransformFeedbackVarying* c =
+      GetCmdSpace<gles2::cmds::GetTransformFeedbackVarying>();
+  if (c) {
+    c->Init(program, index, name_bucket_id, result_shm_id, result_shm_offset);
+  }
+}
+
 void GetUniformBlockIndex(GLuint program,
                           uint32_t name_bucket_id,
                           uint32_t index_shm_id,
@@ -964,6 +1001,17 @@
   }
 }
 
+void GetUniformIndices(GLuint program,
+                       uint32_t names_bucket_id,
+                       uint32_t indices_shm_id,
+                       uint32_t indices_shm_offset) {
+  gles2::cmds::GetUniformIndices* c =
+      GetCmdSpace<gles2::cmds::GetUniformIndices>();
+  if (c) {
+    c->Init(program, names_bucket_id, indices_shm_id, indices_shm_offset);
+  }
+}
+
 void GetUniformLocation(GLuint program,
                         uint32_t name_bucket_id,
                         uint32_t location_shm_id,
@@ -1660,6 +1708,14 @@
   }
 }
 
+void UniformBlockBinding(GLuint program, GLuint index, GLuint binding) {
+  gles2::cmds::UniformBlockBinding* c =
+      GetCmdSpace<gles2::cmds::UniformBlockBinding>();
+  if (c) {
+    c->Init(program, index, binding);
+  }
+}
+
 void UniformMatrix2fvImmediate(GLint location,
                                GLsizei count,
                                const GLfloat* value) {
@@ -2176,6 +2232,22 @@
   }
 }
 
+void GetTransformFeedbackVaryingsCHROMIUM(GLuint program, uint32_t bucket_id) {
+  gles2::cmds::GetTransformFeedbackVaryingsCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::GetTransformFeedbackVaryingsCHROMIUM>();
+  if (c) {
+    c->Init(program, bucket_id);
+  }
+}
+
+void GetUniformsES3CHROMIUM(GLuint program, uint32_t bucket_id) {
+  gles2::cmds::GetUniformsES3CHROMIUM* c =
+      GetCmdSpace<gles2::cmds::GetUniformsES3CHROMIUM>();
+  if (c) {
+    c->Init(program, bucket_id);
+  }
+}
+
 void GetTranslatedShaderSourceANGLE(GLuint shader, uint32_t bucket_id) {
   gles2::cmds::GetTranslatedShaderSourceANGLE* c =
       GetCmdSpace<gles2::cmds::GetTranslatedShaderSourceANGLE>();
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 30f9269..e853766 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -1066,6 +1066,52 @@
   return loc;
 }
 
+bool GLES2Implementation::GetUniformIndicesHelper(
+    GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
+  typedef cmds::GetUniformIndices::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return false;
+  }
+  result->SetNumResults(0);
+  if (!PackStringsToBucket(count, names, NULL, "glGetUniformIndices")) {
+    return false;
+  }
+  helper_->GetUniformIndices(program, kResultBucketId,
+                             GetResultShmId(), GetResultShmOffset());
+  WaitForCmd();
+  if (result->GetNumResults() != count) {
+    return false;
+  }
+  result->CopyResult(indices);
+  return true;
+}
+
+void GLES2Implementation::GetUniformIndices(
+    GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformIndices(" << program
+      << ", " << count << ", " << names << ", " << indices << ")");
+  TRACE_EVENT0("gpu", "GLES2::GetUniformIndices");
+  if (count < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGetUniformIndices", "count < 0");
+    return;
+  }
+  if (count == 0) {
+    return;
+  }
+  bool success = share_group_->program_info_manager()->GetUniformIndices(
+      this, program, count, names, indices);
+  if (success) {
+    GPU_CLIENT_LOG_CODE_BLOCK({
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        GPU_CLIENT_LOG("  " << ii << ": " << indices[ii]);
+      }
+    });
+  }
+  CheckGLError();
+}
+
 bool GLES2Implementation::GetProgramivHelper(
     GLuint program, GLenum pname, GLint* params) {
   bool got_value = share_group_->program_info_manager()->GetProgramiv(
@@ -2363,7 +2409,7 @@
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockName("
       << program << ", " << index << ", " << bufsize << ", "
       << static_cast<const void*>(length) << ", "
-      << static_cast<const void*>(name) << ", ");
+      << static_cast<const void*>(name) << ")");
   if (bufsize < 0) {
     SetGLError(GL_INVALID_VALUE, "glGetActiveUniformBlockName", "bufsize < 0");
     return;
@@ -2380,6 +2426,114 @@
   CheckGLError();
 }
 
+bool GLES2Implementation::GetActiveUniformBlockivHelper(
+    GLuint program, GLuint index, GLenum pname, GLint* params) {
+  typedef cmds::GetActiveUniformBlockiv::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return false;
+  }
+  result->SetNumResults(0);
+  helper_->GetActiveUniformBlockiv(
+      program, index, pname, GetResultShmId(), GetResultShmOffset());
+  WaitForCmd();
+  if (result->GetNumResults() > 0) {
+    if (params) {
+      result->CopyResult(params);
+    }
+    GPU_CLIENT_LOG_CODE_BLOCK({
+      for (int32_t i = 0; i < result->GetNumResults(); ++i) {
+        GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
+      }
+    });
+    return true;
+  }
+  return false;
+}
+
+void GLES2Implementation::GetActiveUniformBlockiv(
+    GLuint program, GLuint index, GLenum pname, GLint* params) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformBlockiv("
+      << program << ", " << index << ", "
+      << GLES2Util::GetStringUniformBlockParameter(pname) << ", "
+      << static_cast<const void*>(params) << ")");
+  TRACE_EVENT0("gpu", "GLES2::GetActiveUniformBlockiv");
+  bool success =
+      share_group_->program_info_manager()->GetActiveUniformBlockiv(
+          this, program, index, pname, params);
+  if (success) {
+    if (params) {
+      // TODO(zmo): For GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, there will
+      // be more than one value returned in params.
+      GPU_CLIENT_LOG("  params: " << params[0]);
+    }
+  }
+  CheckGLError();
+}
+
+bool GLES2Implementation::GetActiveUniformsivHelper(
+    GLuint program, GLsizei count, const GLuint* indices,
+    GLenum pname, GLint* params) {
+  typedef cmds::GetActiveUniformsiv::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return false;
+  }
+  result->SetNumResults(0);
+  base::CheckedNumeric<size_t> bytes = static_cast<size_t>(count);
+  bytes *= sizeof(GLuint);
+  if (!bytes.IsValid()) {
+    SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count overflow");
+    return false;
+  }
+  SetBucketContents(kResultBucketId, indices, bytes.ValueOrDefault(0));
+  helper_->GetActiveUniformsiv(
+      program, kResultBucketId, pname, GetResultShmId(), GetResultShmOffset());
+  WaitForCmd();
+  bool success = result->GetNumResults() == count;
+  if (success) {
+    if (params) {
+      result->CopyResult(params);
+    }
+    GPU_CLIENT_LOG_CODE_BLOCK({
+      for (int32_t i = 0; i < result->GetNumResults(); ++i) {
+        GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
+      }
+    });
+  }
+  helper_->SetBucketSize(kResultBucketId, 0);
+  return success;
+}
+
+void GLES2Implementation::GetActiveUniformsiv(
+    GLuint program, GLsizei count, const GLuint* indices,
+    GLenum pname, GLint* params) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniformsiv("
+      << program << ", " << count << ", "
+      << static_cast<const void*>(indices) << ", "
+      << GLES2Util::GetStringUniformParameter(pname) << ", "
+      << static_cast<const void*>(params) << ")");
+  TRACE_EVENT0("gpu", "GLES2::GetActiveUniformsiv");
+  if (count < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGetActiveUniformsiv", "count < 0");
+    return;
+  }
+  bool success = share_group_->program_info_manager()->GetActiveUniformsiv(
+      this, program, count, indices, pname, params);
+  if (success) {
+    if (params) {
+      GPU_CLIENT_LOG_CODE_BLOCK({
+        for (GLsizei ii = 0; ii < count; ++ii) {
+          GPU_CLIENT_LOG("  " << ii << ": " << params[ii]);
+        }
+      });
+    }
+  }
+  CheckGLError();
+}
+
 void GLES2Implementation::GetAttachedShaders(
     GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
@@ -2522,6 +2676,84 @@
   return result;
 }
 
+bool GLES2Implementation::GetTransformFeedbackVaryingHelper(
+    GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+    GLenum* type, char* name) {
+  // Clear the bucket so if the command fails nothing will be in it.
+  helper_->SetBucketSize(kResultBucketId, 0);
+  typedef cmds::GetTransformFeedbackVarying::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return false;
+  }
+  // Set as failed so if the command fails we'll recover.
+  result->success = false;
+  helper_->GetTransformFeedbackVarying(
+      program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset());
+  WaitForCmd();
+  if (result->success) {
+    if (size) {
+      *size = result->size;
+    }
+    if (type) {
+      *type = result->type;
+    }
+    if (length || name) {
+      std::vector<int8> str;
+      GetBucketContents(kResultBucketId, &str);
+      GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size()));
+      if (max_size > 0) {
+        --max_size;
+      }
+      if (length) {
+        *length = max_size;
+      }
+      if (name) {
+        if (max_size > 0) {
+          memcpy(name, &str[0], max_size);
+          name[max_size] = '\0';
+        } else if (bufsize > 0) {
+          name[0] = '\0';
+        }
+      }
+    }
+  }
+  return result->success != 0;
+}
+
+void GLES2Implementation::GetTransformFeedbackVarying(
+    GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+    GLenum* type, char* name) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTransformFeedbackVarying("
+      << program << ", " << index << ", " << bufsize << ", "
+      << static_cast<const void*>(length) << ", "
+      << static_cast<const void*>(size) << ", "
+      << static_cast<const void*>(type) << ", "
+      << static_cast<const void*>(name) << ", ");
+  if (bufsize < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVarying",
+               "bufsize < 0");
+    return;
+  }
+  TRACE_EVENT0("gpu", "GLES2::GetTransformFeedbackVarying");
+  bool success =
+      share_group_->program_info_manager()->GetTransformFeedbackVarying(
+          this, program, index, bufsize, length, size, type, name);
+  if (success) {
+    if (size) {
+      GPU_CLIENT_LOG("  size: " << *size);
+    }
+    if (type) {
+      GPU_CLIENT_LOG("  type: " << GLES2Util::GetStringEnum(*type));
+    }
+    if (name) {
+      GPU_CLIENT_LOG("  name: " << name);
+    }
+  }
+  CheckGLError();
+}
+
 void GLES2Implementation::GetUniformfv(
     GLuint program, GLint location, GLfloat* params) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
@@ -3628,11 +3860,11 @@
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   if (bufsize < 0) {
     SetGLError(
-        GL_INVALID_VALUE, "glUniformBlocksCHROMIUM", "bufsize less than 0.");
+        GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "bufsize less than 0.");
     return;
   }
   if (size == NULL) {
-    SetGLError(GL_INVALID_VALUE, "glUniformBlocksCHROMIUM", "size is null.");
+    SetGLError(GL_INVALID_VALUE, "glGetUniformBlocksCHROMIUM", "size is null.");
     return;
   }
   // Make sure they've set size to 0 else the value will be undefined on
@@ -3648,8 +3880,91 @@
     return;
   }
   if (static_cast<size_t>(bufsize) < result.size()) {
+    SetGLError(GL_INVALID_OPERATION, "glGetUniformBlocksCHROMIUM",
+               "bufsize is too small for result.");
+    return;
+  }
+  memcpy(info, &result[0], result.size());
+}
+
+void GLES2Implementation::GetUniformsES3CHROMIUMHelper(
+    GLuint program, std::vector<int8>* result) {
+  DCHECK(result);
+  // Clear the bucket so if the command fails nothing will be in it.
+  helper_->SetBucketSize(kResultBucketId, 0);
+  helper_->GetUniformsES3CHROMIUM(program, kResultBucketId);
+  GetBucketContents(kResultBucketId, result);
+}
+
+void GLES2Implementation::GetUniformsES3CHROMIUM(
+    GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  if (bufsize < 0) {
+    SetGLError(
+        GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "bufsize less than 0.");
+    return;
+  }
+  if (size == NULL) {
+    SetGLError(GL_INVALID_VALUE, "glGetUniformsES3CHROMIUM", "size is null.");
+    return;
+  }
+  // Make sure they've set size to 0 else the value will be undefined on
+  // lost context.
+  DCHECK_EQ(0, *size);
+  std::vector<int8> result;
+  GetUniformsES3CHROMIUMHelper(program, &result);
+  if (result.empty()) {
+    return;
+  }
+  *size = result.size();
+  if (!info) {
+    return;
+  }
+  if (static_cast<size_t>(bufsize) < result.size()) {
     SetGLError(GL_INVALID_OPERATION,
-               "glUniformBlocksCHROMIUM", "bufsize is too small for result.");
+               "glGetUniformsES3CHROMIUM", "bufsize is too small for result.");
+    return;
+  }
+  memcpy(info, &result[0], result.size());
+}
+
+void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUMHelper(
+    GLuint program, std::vector<int8>* result) {
+  DCHECK(result);
+  // Clear the bucket so if the command fails nothing will be in it.
+  helper_->SetBucketSize(kResultBucketId, 0);
+  helper_->GetTransformFeedbackVaryingsCHROMIUM(program, kResultBucketId);
+  GetBucketContents(kResultBucketId, result);
+}
+
+void GLES2Implementation::GetTransformFeedbackVaryingsCHROMIUM(
+    GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  if (bufsize < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
+               "bufsize less than 0.");
+    return;
+  }
+  if (size == NULL) {
+    SetGLError(GL_INVALID_VALUE, "glGetTransformFeedbackVaryingsCHROMIUM",
+               "size is null.");
+    return;
+  }
+  // Make sure they've set size to 0 else the value will be undefined on
+  // lost context.
+  DCHECK_EQ(0, *size);
+  std::vector<int8> result;
+  GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
+  if (result.empty()) {
+    return;
+  }
+  *size = result.size();
+  if (!info) {
+    return;
+  }
+  if (static_cast<size_t>(bufsize) < result.size()) {
+    SetGLError(GL_INVALID_OPERATION, "glGetTransformFeedbackVaryingsCHROMIUM",
+               "bufsize is too small for result.");
     return;
   }
   memcpy(info, &result[0], result.size());
@@ -4528,6 +4843,94 @@
   return false;
 }
 
+bool GLES2Implementation::PackStringsToBucket(GLsizei count,
+                                              const char* const* str,
+                                              const GLint* length,
+                                              const char* func_name) {
+  DCHECK_LE(0, count);
+  // Compute the total size.
+  base::CheckedNumeric<size_t> total_size = count;
+  total_size += 1;
+  total_size *= sizeof(GLint);
+  if (!total_size.IsValid()) {
+    SetGLError(GL_INVALID_VALUE, func_name, "overflow");
+    return false;
+  }
+  size_t header_size = total_size.ValueOrDefault(0);
+  std::vector<GLint> header(count + 1);
+  header[0] = static_cast<GLint>(count);
+  for (GLsizei ii = 0; ii < count; ++ii) {
+    GLint len = 0;
+    if (str[ii]) {
+      len = (length && length[ii] >= 0)
+                ? length[ii]
+                : base::checked_cast<GLint>(strlen(str[ii]));
+    }
+    total_size += len;
+    total_size += 1;  // NULL at the end of each char array.
+    if (!total_size.IsValid()) {
+      SetGLError(GL_INVALID_VALUE, func_name, "overflow");
+      return false;
+    }
+    header[ii + 1] = len;
+  }
+  // Pack data into a bucket on the service.
+  helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
+  size_t offset = 0;
+  for (GLsizei ii = 0; ii <= count; ++ii) {
+    const char* src =
+        (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
+    base::CheckedNumeric<size_t> checked_size =
+        (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
+    if (ii > 0) {
+      checked_size += 1;  // NULL in the end.
+    }
+    if (!checked_size.IsValid()) {
+      SetGLError(GL_INVALID_VALUE, func_name, "overflow");
+      return false;
+    }
+    size_t size = checked_size.ValueOrDefault(0);
+    while (size) {
+      ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
+      if (!buffer.valid() || buffer.size() == 0) {
+        SetGLError(GL_OUT_OF_MEMORY, func_name, "too large");
+        return false;
+      }
+      size_t copy_size = buffer.size();
+      if (ii > 0 && buffer.size() == size)
+        --copy_size;
+      if (copy_size)
+        memcpy(buffer.address(), src, copy_size);
+      if (copy_size < buffer.size()) {
+        // Append NULL in the end.
+        DCHECK(copy_size + 1 == buffer.size());
+        char* str = reinterpret_cast<char*>(buffer.address());
+        str[copy_size] = 0;
+      }
+      helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
+                             buffer.shm_id(), buffer.offset());
+      offset += buffer.size();
+      src += buffer.size();
+      size -= buffer.size();
+    }
+  }
+  DCHECK_EQ(total_size.ValueOrDefault(0), offset);
+  return true;
+}
+
+void GLES2Implementation::UniformBlockBinding(GLuint program,
+                                              GLuint index,
+                                              GLuint binding) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformBlockBinding(" << program
+                     << ", " << index << ", " << binding << ")");
+  share_group_->program_info_manager()->UniformBlockBinding(
+      this, program, index, binding);
+  helper_->UniformBlockBinding(program, index, binding);
+  CheckGLError();
+}
+
+
 // Include the auto-generated part of this file. We split this because it means
 // we can easily edit the non-auto generated parts right here in this file
 // instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 193fbb8..4e8ae5f 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -222,10 +222,24 @@
       GLint* size, GLenum* type, char* name);
   void GetUniformBlocksCHROMIUMHelper(
       GLuint program, std::vector<int8>* result);
+  void GetUniformsES3CHROMIUMHelper(
+      GLuint program, std::vector<int8>* result);
   GLuint GetUniformBlockIndexHelper(GLuint program, const char* name);
   bool GetActiveUniformBlockNameHelper(
       GLuint program, GLuint index, GLsizei bufsize,
       GLsizei* length, char* name);
+  bool GetActiveUniformBlockivHelper(
+      GLuint program, GLuint index, GLenum pname, GLint* params);
+  void GetTransformFeedbackVaryingsCHROMIUMHelper(
+      GLuint program, std::vector<int8>* result);
+  bool GetTransformFeedbackVaryingHelper(
+      GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+      GLint* size, GLenum* type, char* name);
+  bool GetUniformIndicesHelper(
+      GLuint program, GLsizei count, const char* const* names, GLuint* indices);
+  bool GetActiveUniformsivHelper(
+      GLuint program, GLsizei count, const GLuint* indices,
+      GLenum pname, GLint* params);
 
   void FreeUnusedSharedMemory();
   void FreeEverything();
@@ -625,6 +639,13 @@
       GLuint buffer_id,
       const char* function_name, GLuint offset, GLsizei size);
 
+  // Pack 2D arrays of char into a bucket.
+  // Helper function for ShaderSource(), TransformFeedbackVaryings(), etc.
+  bool PackStringsToBucket(GLsizei count,
+                           const char* const* str,
+                           const GLint* length,
+                           const char* func_name);
+
   const std::string& GetLogPrefix() const;
 
 #if defined(GL_CLIENT_FAIL_GL_ERRORS)
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 3d6009a..9d2d8eb 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -255,12 +255,23 @@
                       GLenum* type,
                       char* name) override;
 
+void GetActiveUniformBlockiv(GLuint program,
+                             GLuint index,
+                             GLenum pname,
+                             GLint* params) override;
+
 void GetActiveUniformBlockName(GLuint program,
                                GLuint index,
                                GLsizei bufsize,
                                GLsizei* length,
                                char* name) override;
 
+void GetActiveUniformsiv(GLuint program,
+                         GLsizei count,
+                         const GLuint* indices,
+                         GLenum pname,
+                         GLint* params) override;
+
 void GetAttachedShaders(GLuint program,
                         GLsizei maxcount,
                         GLsizei* count,
@@ -333,12 +344,25 @@
 
 void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) override;
 
+void GetTransformFeedbackVarying(GLuint program,
+                                 GLuint index,
+                                 GLsizei bufsize,
+                                 GLsizei* length,
+                                 GLsizei* size,
+                                 GLenum* type,
+                                 char* name) override;
+
 GLuint GetUniformBlockIndex(GLuint program, const char* name) override;
 
 void GetUniformfv(GLuint program, GLint location, GLfloat* params) override;
 
 void GetUniformiv(GLuint program, GLint location, GLint* params) override;
 
+void GetUniformIndices(GLuint program,
+                       GLsizei count,
+                       const char* const* names,
+                       GLuint* indices) override;
+
 GLint GetUniformLocation(GLuint program, const char* name) override;
 
 void GetVertexAttribPointerv(GLuint index,
@@ -580,6 +604,8 @@
 
 void Uniform4uiv(GLint location, GLsizei count, const GLuint* v) override;
 
+void UniformBlockBinding(GLuint program, GLuint index, GLuint binding) override;
+
 void UniformMatrix2fv(GLint location,
                       GLsizei count,
                       GLboolean transpose,
@@ -794,6 +820,16 @@
                               GLsizei* size,
                               void* info) override;
 
+void GetTransformFeedbackVaryingsCHROMIUM(GLuint program,
+                                          GLsizei bufsize,
+                                          GLsizei* size,
+                                          void* info) override;
+
+void GetUniformsES3CHROMIUM(GLuint program,
+                            GLsizei bufsize,
+                            GLsizei* size,
+                            void* info) override;
+
 GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
 
 GLuint CreateImageCHROMIUM(ClientBuffer buffer,
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index d84c123..625c747 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -1747,73 +1747,10 @@
     SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
     return;
   }
-  // Compute the total size.
-  base::CheckedNumeric<size_t> total_size = count;
-  total_size += 1;
-  total_size *= sizeof(GLint);
-  if (!total_size.IsValid()) {
-    SetGLError(GL_INVALID_VALUE, "glShaderSource", "overflow");
+
+  if (!PackStringsToBucket(count, str, length, "glShaderSource")) {
     return;
   }
-  size_t header_size = total_size.ValueOrDefault(0);
-  std::vector<GLint> header(count + 1);
-  header[0] = static_cast<GLint>(count);
-  for (GLsizei ii = 0; ii < count; ++ii) {
-    GLint len = 0;
-    if (str[ii]) {
-      len = (length && length[ii] >= 0)
-                ? length[ii]
-                : base::checked_cast<GLint>(strlen(str[ii]));
-    }
-    total_size += len;
-    total_size += 1;  // NULL at the end of each char array.
-    if (!total_size.IsValid()) {
-      SetGLError(GL_INVALID_VALUE, "glShaderSource", "overflow");
-      return;
-    }
-    header[ii + 1] = len;
-  }
-  // Pack data into a bucket on the service.
-  helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
-  size_t offset = 0;
-  for (GLsizei ii = 0; ii <= count; ++ii) {
-    const char* src =
-        (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1];
-    base::CheckedNumeric<size_t> checked_size =
-        (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
-    if (ii > 0) {
-      checked_size += 1;  // NULL in the end.
-    }
-    if (!checked_size.IsValid()) {
-      SetGLError(GL_INVALID_VALUE, "glShaderSource", "overflow");
-      return;
-    }
-    size_t size = checked_size.ValueOrDefault(0);
-    while (size) {
-      ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
-      if (!buffer.valid() || buffer.size() == 0) {
-        SetGLError(GL_OUT_OF_MEMORY, "glShaderSource", "too large");
-        return;
-      }
-      size_t copy_size = buffer.size();
-      if (ii > 0 && buffer.size() == size)
-        --copy_size;
-      if (copy_size)
-        memcpy(buffer.address(), src, copy_size);
-      if (copy_size < buffer.size()) {
-        // Append NULL in the end.
-        DCHECK(copy_size + 1 == buffer.size());
-        char* str = reinterpret_cast<char*>(buffer.address());
-        str[copy_size] = 0;
-      }
-      helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
-                             buffer.shm_id(), buffer.offset());
-      offset += buffer.size();
-      src += buffer.size();
-      size -= buffer.size();
-    }
-  }
-  DCHECK_EQ(total_size.ValueOrDefault(0), offset);
   helper_->ShaderSourceBucket(shader, kResultBucketId);
   helper_->SetBucketSize(kResultBucketId, 0);
   CheckGLError();
@@ -1990,72 +1927,11 @@
     SetGLError(GL_INVALID_VALUE, "glTransformFeedbackVaryings", "count < 0");
     return;
   }
-  // Compute the total size.
-  base::CheckedNumeric<size_t> total_size = count;
-  total_size += 1;
-  total_size *= sizeof(GLint);
-  if (!total_size.IsValid()) {
-    SetGLError(GL_INVALID_VALUE, "glTransformFeedbackVaryings", "overflow");
+
+  if (!PackStringsToBucket(count, varyings, NULL,
+                           "glTransformFeedbackVaryings")) {
     return;
   }
-  size_t header_size = total_size.ValueOrDefault(0);
-  std::vector<GLint> header(count + 1);
-  header[0] = static_cast<GLint>(count);
-  for (GLsizei ii = 0; ii < count; ++ii) {
-    GLint len = 0;
-    if (varyings[ii]) {
-      len = static_cast<GLint>(strlen(varyings[ii]));
-    }
-    total_size += len;
-    total_size += 1;  // NULL at the end of each char array.
-    if (!total_size.IsValid()) {
-      SetGLError(GL_INVALID_VALUE, "glTransformFeedbackVaryings", "overflow");
-      return;
-    }
-    header[ii + 1] = len;
-  }
-  // Pack data into a bucket on the service.
-  helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0));
-  size_t offset = 0;
-  for (GLsizei ii = 0; ii <= count; ++ii) {
-    const char* src = (ii == 0) ? reinterpret_cast<const char*>(&header[0])
-                                : varyings[ii - 1];
-    base::CheckedNumeric<size_t> checked_size =
-        (ii == 0) ? header_size : static_cast<size_t>(header[ii]);
-    if (ii > 0) {
-      checked_size += 1;  // NULL in the end.
-    }
-    if (!checked_size.IsValid()) {
-      SetGLError(GL_INVALID_VALUE, "glTransformFeedbackVaryings", "overflow");
-      return;
-    }
-    size_t size = checked_size.ValueOrDefault(0);
-    while (size) {
-      ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
-      if (!buffer.valid() || buffer.size() == 0) {
-        SetGLError(GL_OUT_OF_MEMORY, "glTransformFeedbackVaryings",
-                   "too large");
-        return;
-      }
-      size_t copy_size = buffer.size();
-      if (ii > 0 && buffer.size() == size)
-        --copy_size;
-      if (copy_size)
-        memcpy(buffer.address(), src, copy_size);
-      if (copy_size < buffer.size()) {
-        // Append NULL in the end.
-        DCHECK(copy_size + 1 == buffer.size());
-        char* str = reinterpret_cast<char*>(buffer.address());
-        str[copy_size] = 0;
-      }
-      helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
-                             buffer.shm_id(), buffer.offset());
-      offset += buffer.size();
-      src += buffer.size();
-      size -= buffer.size();
-    }
-  }
-  DCHECK_EQ(total_size.ValueOrDefault(0), offset);
   helper_->TransformFeedbackVaryingsBucket(program, kResultBucketId,
                                            buffermode);
   helper_->SetBucketSize(kResultBucketId, 0);
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index 6dbcdcc..8b02ad9 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -751,7 +751,9 @@
 }
 // TODO(zmo): Implement unit test for GetActiveAttrib
 // TODO(zmo): Implement unit test for GetActiveUniform
+// TODO(zmo): Implement unit test for GetActiveUniformBlockiv
 // TODO(zmo): Implement unit test for GetActiveUniformBlockName
+// TODO(zmo): Implement unit test for GetActiveUniformsiv
 // TODO(zmo): Implement unit test for GetAttachedShaders
 // TODO(zmo): Implement unit test for GetAttribLocation
 
@@ -984,9 +986,11 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
   EXPECT_EQ(static_cast<Result::Type>(1), result);
 }
+// TODO(zmo): Implement unit test for GetTransformFeedbackVarying
 // TODO(zmo): Implement unit test for GetUniformBlockIndex
 // TODO(zmo): Implement unit test for GetUniformfv
 // TODO(zmo): Implement unit test for GetUniformiv
+// TODO(zmo): Implement unit test for GetUniformIndices
 // TODO(zmo): Implement unit test for GetUniformLocation
 
 TEST_F(GLES2ImplementationTest, GetVertexAttribfv) {
@@ -2032,6 +2036,17 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, UniformBlockBinding) {
+  struct Cmds {
+    cmds::UniformBlockBinding cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(1, 2, 3);
+
+  gl_->UniformBlockBinding(1, 2, 3);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, UniformMatrix2fv) {
   GLfloat data[2][4] = {{0}};
   struct Cmds {
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 352ff78..990e701 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -186,11 +186,20 @@
                               GLint* size,
                               GLenum* type,
                               char* name) = 0;
+virtual void GetActiveUniformBlockiv(GLuint program,
+                                     GLuint index,
+                                     GLenum pname,
+                                     GLint* params) = 0;
 virtual void GetActiveUniformBlockName(GLuint program,
                                        GLuint index,
                                        GLsizei bufsize,
                                        GLsizei* length,
                                        char* name) = 0;
+virtual void GetActiveUniformsiv(GLuint program,
+                                 GLsizei count,
+                                 const GLuint* indices,
+                                 GLenum pname,
+                                 GLint* params) = 0;
 virtual void GetAttachedShaders(GLuint program,
                                 GLsizei maxcount,
                                 GLsizei* count,
@@ -245,9 +254,20 @@
                                GLenum pname,
                                GLfloat* params) = 0;
 virtual void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) = 0;
+virtual void GetTransformFeedbackVarying(GLuint program,
+                                         GLuint index,
+                                         GLsizei bufsize,
+                                         GLsizei* length,
+                                         GLsizei* size,
+                                         GLenum* type,
+                                         char* name) = 0;
 virtual GLuint GetUniformBlockIndex(GLuint program, const char* name) = 0;
 virtual void GetUniformfv(GLuint program, GLint location, GLfloat* params) = 0;
 virtual void GetUniformiv(GLuint program, GLint location, GLint* params) = 0;
+virtual void GetUniformIndices(GLuint program,
+                               GLsizei count,
+                               const char* const* names,
+                               GLuint* indices) = 0;
 virtual GLint GetUniformLocation(GLuint program, const char* name) = 0;
 virtual void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) = 0;
 virtual void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) = 0;
@@ -417,6 +437,9 @@
                         GLuint z,
                         GLuint w) = 0;
 virtual void Uniform4uiv(GLint location, GLsizei count, const GLuint* v) = 0;
+virtual void UniformBlockBinding(GLuint program,
+                                 GLuint index,
+                                 GLuint binding) = 0;
 virtual void UniformMatrix2fv(GLint location,
                               GLsizei count,
                               GLboolean transpose,
@@ -575,6 +598,14 @@
                                       GLsizei bufsize,
                                       GLsizei* size,
                                       void* info) = 0;
+virtual void GetTransformFeedbackVaryingsCHROMIUM(GLuint program,
+                                                  GLsizei bufsize,
+                                                  GLsizei* size,
+                                                  void* info) = 0;
+virtual void GetUniformsES3CHROMIUM(GLuint program,
+                                    GLsizei bufsize,
+                                    GLsizei* size,
+                                    void* info) = 0;
 virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) = 0;
 virtual GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                                    GLsizei width,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 0ca5199..f020e14 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -185,11 +185,20 @@
                       GLint* size,
                       GLenum* type,
                       char* name) override;
+void GetActiveUniformBlockiv(GLuint program,
+                             GLuint index,
+                             GLenum pname,
+                             GLint* params) override;
 void GetActiveUniformBlockName(GLuint program,
                                GLuint index,
                                GLsizei bufsize,
                                GLsizei* length,
                                char* name) override;
+void GetActiveUniformsiv(GLuint program,
+                         GLsizei count,
+                         const GLuint* indices,
+                         GLenum pname,
+                         GLint* params) override;
 void GetAttachedShaders(GLuint program,
                         GLsizei maxcount,
                         GLsizei* count,
@@ -240,9 +249,20 @@
 const GLubyte* GetString(GLenum name) override;
 void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) override;
 void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) override;
+void GetTransformFeedbackVarying(GLuint program,
+                                 GLuint index,
+                                 GLsizei bufsize,
+                                 GLsizei* length,
+                                 GLsizei* size,
+                                 GLenum* type,
+                                 char* name) override;
 GLuint GetUniformBlockIndex(GLuint program, const char* name) override;
 void GetUniformfv(GLuint program, GLint location, GLfloat* params) override;
 void GetUniformiv(GLuint program, GLint location, GLint* params) override;
+void GetUniformIndices(GLuint program,
+                       GLsizei count,
+                       const char* const* names,
+                       GLuint* indices) override;
 GLint GetUniformLocation(GLuint program, const char* name) override;
 void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) override;
 void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) override;
@@ -410,6 +430,7 @@
                 GLuint z,
                 GLuint w) override;
 void Uniform4uiv(GLint location, GLsizei count, const GLuint* v) override;
+void UniformBlockBinding(GLuint program, GLuint index, GLuint binding) override;
 void UniformMatrix2fv(GLint location,
                       GLsizei count,
                       GLboolean transpose,
@@ -562,6 +583,14 @@
                               GLsizei bufsize,
                               GLsizei* size,
                               void* info) override;
+void GetTransformFeedbackVaryingsCHROMIUM(GLuint program,
+                                          GLsizei bufsize,
+                                          GLsizei* size,
+                                          void* info) override;
+void GetUniformsES3CHROMIUM(GLuint program,
+                            GLsizei bufsize,
+                            GLsizei* size,
+                            void* info) override;
 GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
 GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                            GLsizei width,
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 2a6f88e..15f2912 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -286,12 +286,23 @@
                                           GLenum* /* type */,
                                           char* /* name */) {
 }
+void GLES2InterfaceStub::GetActiveUniformBlockiv(GLuint /* program */,
+                                                 GLuint /* index */,
+                                                 GLenum /* pname */,
+                                                 GLint* /* params */) {
+}
 void GLES2InterfaceStub::GetActiveUniformBlockName(GLuint /* program */,
                                                    GLuint /* index */,
                                                    GLsizei /* bufsize */,
                                                    GLsizei* /* length */,
                                                    char* /* name */) {
 }
+void GLES2InterfaceStub::GetActiveUniformsiv(GLuint /* program */,
+                                             GLsizei /* count */,
+                                             const GLuint* /* indices */,
+                                             GLenum /* pname */,
+                                             GLint* /* params */) {
+}
 void GLES2InterfaceStub::GetAttachedShaders(GLuint /* program */,
                                             GLsizei /* maxcount */,
                                             GLsizei* /* count */,
@@ -382,6 +393,14 @@
                                            GLenum /* pname */,
                                            GLint* /* params */) {
 }
+void GLES2InterfaceStub::GetTransformFeedbackVarying(GLuint /* program */,
+                                                     GLuint /* index */,
+                                                     GLsizei /* bufsize */,
+                                                     GLsizei* /* length */,
+                                                     GLsizei* /* size */,
+                                                     GLenum* /* type */,
+                                                     char* /* name */) {
+}
 GLuint GLES2InterfaceStub::GetUniformBlockIndex(GLuint /* program */,
                                                 const char* /* name */) {
   return 0;
@@ -394,6 +413,11 @@
                                       GLint /* location */,
                                       GLint* /* params */) {
 }
+void GLES2InterfaceStub::GetUniformIndices(GLuint /* program */,
+                                           GLsizei /* count */,
+                                           const char* const* /* names */,
+                                           GLuint* /* indices */) {
+}
 GLint GLES2InterfaceStub::GetUniformLocation(GLuint /* program */,
                                              const char* /* name */) {
   return 0;
@@ -722,6 +746,10 @@
                                      GLsizei /* count */,
                                      const GLuint* /* v */) {
 }
+void GLES2InterfaceStub::UniformBlockBinding(GLuint /* program */,
+                                             GLuint /* index */,
+                                             GLuint /* binding */) {
+}
 void GLES2InterfaceStub::UniformMatrix2fv(GLint /* location */,
                                           GLsizei /* count */,
                                           GLboolean /* transpose */,
@@ -978,6 +1006,17 @@
                                                   GLsizei* /* size */,
                                                   void* /* info */) {
 }
+void GLES2InterfaceStub::GetTransformFeedbackVaryingsCHROMIUM(
+    GLuint /* program */,
+    GLsizei /* bufsize */,
+    GLsizei* /* size */,
+    void* /* info */) {
+}
+void GLES2InterfaceStub::GetUniformsES3CHROMIUM(GLuint /* program */,
+                                                GLsizei /* bufsize */,
+                                                GLsizei* /* size */,
+                                                void* /* info */) {
+}
 GLuint GLES2InterfaceStub::CreateStreamTextureCHROMIUM(GLuint /* texture */) {
   return 0;
 }
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index da97a87..66deca4 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -185,11 +185,20 @@
                       GLint* size,
                       GLenum* type,
                       char* name) override;
+void GetActiveUniformBlockiv(GLuint program,
+                             GLuint index,
+                             GLenum pname,
+                             GLint* params) override;
 void GetActiveUniformBlockName(GLuint program,
                                GLuint index,
                                GLsizei bufsize,
                                GLsizei* length,
                                char* name) override;
+void GetActiveUniformsiv(GLuint program,
+                         GLsizei count,
+                         const GLuint* indices,
+                         GLenum pname,
+                         GLint* params) override;
 void GetAttachedShaders(GLuint program,
                         GLsizei maxcount,
                         GLsizei* count,
@@ -240,9 +249,20 @@
 const GLubyte* GetString(GLenum name) override;
 void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) override;
 void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) override;
+void GetTransformFeedbackVarying(GLuint program,
+                                 GLuint index,
+                                 GLsizei bufsize,
+                                 GLsizei* length,
+                                 GLsizei* size,
+                                 GLenum* type,
+                                 char* name) override;
 GLuint GetUniformBlockIndex(GLuint program, const char* name) override;
 void GetUniformfv(GLuint program, GLint location, GLfloat* params) override;
 void GetUniformiv(GLuint program, GLint location, GLint* params) override;
+void GetUniformIndices(GLuint program,
+                       GLsizei count,
+                       const char* const* names,
+                       GLuint* indices) override;
 GLint GetUniformLocation(GLuint program, const char* name) override;
 void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) override;
 void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) override;
@@ -410,6 +430,7 @@
                 GLuint z,
                 GLuint w) override;
 void Uniform4uiv(GLint location, GLsizei count, const GLuint* v) override;
+void UniformBlockBinding(GLuint program, GLuint index, GLuint binding) override;
 void UniformMatrix2fv(GLint location,
                       GLsizei count,
                       GLboolean transpose,
@@ -562,6 +583,14 @@
                               GLsizei bufsize,
                               GLsizei* size,
                               void* info) override;
+void GetTransformFeedbackVaryingsCHROMIUM(GLuint program,
+                                          GLsizei bufsize,
+                                          GLsizei* size,
+                                          void* info) override;
+void GetUniformsES3CHROMIUM(GLuint program,
+                            GLsizei bufsize,
+                            GLsizei* size,
+                            void* info) override;
 GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
 GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                            GLsizei width,
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 df03be5..79fd529 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -500,6 +500,14 @@
   gl_->GetActiveUniform(program, index, bufsize, length, size, type, name);
 }
 
+void GLES2TraceImplementation::GetActiveUniformBlockiv(GLuint program,
+                                                       GLuint index,
+                                                       GLenum pname,
+                                                       GLint* params) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetActiveUniformBlockiv");
+  gl_->GetActiveUniformBlockiv(program, index, pname, params);
+}
+
 void GLES2TraceImplementation::GetActiveUniformBlockName(GLuint program,
                                                          GLuint index,
                                                          GLsizei bufsize,
@@ -509,6 +517,15 @@
   gl_->GetActiveUniformBlockName(program, index, bufsize, length, name);
 }
 
+void GLES2TraceImplementation::GetActiveUniformsiv(GLuint program,
+                                                   GLsizei count,
+                                                   const GLuint* indices,
+                                                   GLenum pname,
+                                                   GLint* params) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetActiveUniformsiv");
+  gl_->GetActiveUniformsiv(program, count, indices, pname, params);
+}
+
 void GLES2TraceImplementation::GetAttachedShaders(GLuint program,
                                                   GLsizei maxcount,
                                                   GLsizei* count,
@@ -662,6 +679,19 @@
   gl_->GetTexParameteriv(target, pname, params);
 }
 
+void GLES2TraceImplementation::GetTransformFeedbackVarying(GLuint program,
+                                                           GLuint index,
+                                                           GLsizei bufsize,
+                                                           GLsizei* length,
+                                                           GLsizei* size,
+                                                           GLenum* type,
+                                                           char* name) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "GLES2Trace::GetTransformFeedbackVarying");
+  gl_->GetTransformFeedbackVarying(program, index, bufsize, length, size, type,
+                                   name);
+}
+
 GLuint GLES2TraceImplementation::GetUniformBlockIndex(GLuint program,
                                                       const char* name) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetUniformBlockIndex");
@@ -682,6 +712,14 @@
   gl_->GetUniformiv(program, location, params);
 }
 
+void GLES2TraceImplementation::GetUniformIndices(GLuint program,
+                                                 GLsizei count,
+                                                 const char* const* names,
+                                                 GLuint* indices) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetUniformIndices");
+  gl_->GetUniformIndices(program, count, names, indices);
+}
+
 GLint GLES2TraceImplementation::GetUniformLocation(GLuint program,
                                                    const char* name) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetUniformLocation");
@@ -1230,6 +1268,13 @@
   gl_->Uniform4uiv(location, count, v);
 }
 
+void GLES2TraceImplementation::UniformBlockBinding(GLuint program,
+                                                   GLuint index,
+                                                   GLuint binding) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UniformBlockBinding");
+  gl_->UniformBlockBinding(program, index, binding);
+}
+
 void GLES2TraceImplementation::UniformMatrix2fv(GLint location,
                                                 GLsizei count,
                                                 GLboolean transpose,
@@ -1675,6 +1720,24 @@
   gl_->GetUniformBlocksCHROMIUM(program, bufsize, size, info);
 }
 
+void GLES2TraceImplementation::GetTransformFeedbackVaryingsCHROMIUM(
+    GLuint program,
+    GLsizei bufsize,
+    GLsizei* size,
+    void* info) {
+  TRACE_EVENT_BINARY_EFFICIENT0(
+      "gpu", "GLES2Trace::GetTransformFeedbackVaryingsCHROMIUM");
+  gl_->GetTransformFeedbackVaryingsCHROMIUM(program, bufsize, size, info);
+}
+
+void GLES2TraceImplementation::GetUniformsES3CHROMIUM(GLuint program,
+                                                      GLsizei bufsize,
+                                                      GLsizei* size,
+                                                      void* info) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetUniformsES3CHROMIUM");
+  gl_->GetUniformsES3CHROMIUM(program, bufsize, size, info);
+}
+
 GLuint GLES2TraceImplementation::CreateStreamTextureCHROMIUM(GLuint texture) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu",
                                 "GLES2Trace::CreateStreamTextureCHROMIUM");
diff --git a/gpu/command_buffer/client/gpu_control.h b/gpu/command_buffer/client/gpu_control.h
index a56bd51..2b303b3 100644
--- a/gpu/command_buffer/client/gpu_control.h
+++ b/gpu/command_buffer/client/gpu_control.h
@@ -17,6 +17,10 @@
 
 extern "C" typedef struct _ClientBuffer* ClientBuffer;
 
+namespace base {
+class Lock;
+}
+
 namespace gfx {
 class GpuMemoryBuffer;
 }
@@ -75,6 +79,12 @@
   // returns a stream identifier.
   virtual uint32_t CreateStreamTexture(uint32_t texture_id) = 0;
 
+  // Sets a lock this will be held on every callback from the GPU
+  // implementation. This lock must be set and must be held on every call into
+  // the GPU implementation if it is to be used from multiple threads. This
+  // may not be supported with all implementations.
+  virtual void SetLock(base::Lock*) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(GpuControl);
 };
diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc
index 04121aa..779d914 100644
--- a/gpu/command_buffer/client/program_info_manager.cc
+++ b/gpu/command_buffer/client/program_info_manager.cc
@@ -44,6 +44,17 @@
 ProgramInfoManager::Program::UniformInfo::~UniformInfo() {
 }
 
+ProgramInfoManager::Program::UniformES3::UniformES3()
+    : block_index(-1),
+      offset(-1),
+      array_stride(-1),
+      matrix_stride(-1),
+      is_row_major(0) {
+}
+
+ProgramInfoManager::Program::UniformES3::~UniformES3() {
+}
+
 ProgramInfoManager::Program::UniformBlock::UniformBlock()
     : binding(0),
       data_size(0),
@@ -54,13 +65,26 @@
 ProgramInfoManager::Program::UniformBlock::~UniformBlock() {
 }
 
+ProgramInfoManager::Program::TransformFeedbackVarying::
+TransformFeedbackVarying()
+    : size(0),
+      type(0) {
+}
+
+ProgramInfoManager::Program::TransformFeedbackVarying::
+~TransformFeedbackVarying() {
+}
+
 ProgramInfoManager::Program::Program()
     : cached_es2_(false),
       max_attrib_name_length_(0),
       max_uniform_name_length_(0),
       link_status_(false),
       cached_es3_uniform_blocks_(false),
-      active_uniform_block_max_name_length_(0) {
+      active_uniform_block_max_name_length_(0),
+      cached_es3_transform_feedback_varyings_(false),
+      transform_feedback_varying_max_length_(0),
+      cached_es3_uniformsiv_(false) {
 }
 
 ProgramInfoManager::Program::~Program() {
@@ -124,6 +148,22 @@
   return -1;
 }
 
+GLuint ProgramInfoManager::Program::GetUniformIndex(
+    const std::string& name) const {
+  // TODO(zmo): Maybe build a hashed_map for faster lookup.
+  for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
+    const UniformInfo& info = uniform_infos_[ii];
+    // For an array, either "var" or "var[0]" is considered as a match.
+    // See "OpenGL ES 3.0.0, Section 2.11.3 Program Objects."
+    if (info.name == name ||
+        (info.is_array &&
+         info.name.compare(0, info.name.size() - 3, name) == 0)) {
+      return ii;
+    }
+  }
+  return GL_INVALID_INDEX;
+}
+
 GLint ProgramInfoManager::Program::GetFragDataLocation(
     const std::string& name) const {
   base::hash_map<std::string, GLint>::const_iterator iter =
@@ -162,6 +202,12 @@
     case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
       *params = static_cast<GLint>(active_uniform_block_max_name_length_);
       return true;
+    case GL_TRANSFORM_FEEDBACK_VARYINGS:
+      *params = static_cast<GLint>(transform_feedback_varyings_.size());
+      return true;
+    case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+      *params = static_cast<GLint>(transform_feedback_varying_max_length_);
+      return true;
     default:
       NOTREACHED();
       break;
@@ -179,6 +225,98 @@
   return GL_INVALID_INDEX;
 }
 
+void ProgramInfoManager::Program::UniformBlockBinding(
+    GLuint index , GLuint binding) {
+  if (index < uniform_blocks_.size()) {
+    uniform_blocks_[index].binding = binding;
+  }
+}
+
+const ProgramInfoManager::Program::TransformFeedbackVarying*
+ProgramInfoManager::Program::GetTransformFeedbackVarying(GLuint index) const {
+  return (index < transform_feedback_varyings_.size()) ?
+      &transform_feedback_varyings_[index] : NULL;
+}
+
+bool ProgramInfoManager::Program::GetUniformsiv(
+    GLsizei count, const GLuint* indices, GLenum pname, GLint* params) {
+  if (count == 0) {
+    // At this point, pname has already been validated.
+    return true;
+  }
+  DCHECK(count > 0 && indices);
+  size_t num_uniforms = uniform_infos_.size();
+  if (num_uniforms == 0) {
+    num_uniforms = uniforms_es3_.size();
+  }
+  if (static_cast<size_t>(count) > num_uniforms) {
+    return false;
+  }
+  for (GLsizei ii = 0; ii < count; ++ii) {
+    if (indices[ii] >= num_uniforms) {
+      return false;
+    }
+  }
+  if (!params) {
+    return true;
+  }
+  switch (pname) {
+    case GL_UNIFORM_SIZE:
+      DCHECK_EQ(num_uniforms, uniform_infos_.size());
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        params[ii] = static_cast<GLint>(uniform_infos_[indices[ii]].size);
+      }
+      return true;
+    case GL_UNIFORM_TYPE:
+      DCHECK_EQ(num_uniforms, uniform_infos_.size());
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        params[ii] = static_cast<GLint>(uniform_infos_[indices[ii]].type);
+      }
+      return true;
+    case GL_UNIFORM_NAME_LENGTH:
+      DCHECK_EQ(num_uniforms, uniform_infos_.size());
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        params[ii] = static_cast<GLint>(
+            uniform_infos_[indices[ii]].name.length() + 1);
+      }
+      return true;
+    case GL_UNIFORM_BLOCK_INDEX:
+      DCHECK_EQ(num_uniforms, uniforms_es3_.size());
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        params[ii] = uniforms_es3_[indices[ii]].block_index;
+      }
+      return true;
+    case GL_UNIFORM_OFFSET:
+      DCHECK_EQ(num_uniforms, uniforms_es3_.size());
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        params[ii] = uniforms_es3_[indices[ii]].offset;
+      }
+      return true;
+    case GL_UNIFORM_ARRAY_STRIDE:
+      DCHECK_EQ(num_uniforms, uniforms_es3_.size());
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        params[ii] = uniforms_es3_[indices[ii]].array_stride;
+      }
+      return true;
+    case GL_UNIFORM_MATRIX_STRIDE:
+      DCHECK_EQ(num_uniforms, uniforms_es3_.size());
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        params[ii] = uniforms_es3_[indices[ii]].matrix_stride;
+      }
+      return true;
+    case GL_UNIFORM_IS_ROW_MAJOR:
+      DCHECK_EQ(num_uniforms, uniforms_es3_.size());
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        params[ii] = uniforms_es3_[indices[ii]].is_row_major;
+      }
+      return true;
+    default:
+      NOTREACHED();
+      break;
+  }
+  return false;
+}
+
 void ProgramInfoManager::Program::UpdateES2(const std::vector<int8>& result) {
   if (cached_es2_) {
     return;
@@ -306,12 +444,119 @@
   cached_es3_uniform_blocks_ = true;
 }
 
+void ProgramInfoManager::Program::UpdateES3Uniformsiv(
+    const std::vector<int8>& result) {
+  if (cached_es3_uniformsiv_) {
+    return;
+  }
+  if (result.empty()) {
+    // This should only happen on a lost context.
+    return;
+  }
+  uniforms_es3_.clear();
+
+  // |result| comes from GPU process. We consider it trusted data. Therefore,
+  // no need to check for overflows as the GPU side did the checks already.
+  uint32_t header_size = sizeof(UniformsES3Header);
+  DCHECK_GE(result.size(), header_size);
+  const UniformsES3Header* header = LocalGetAs<const UniformsES3Header*>(
+      result, 0, header_size);
+  DCHECK(header);
+  if (header->num_uniforms == 0) {
+    DCHECK_EQ(result.size(), header_size);
+    // TODO(zmo): Here we can't tell if no uniforms are defined, or
+    // the previous link failed.
+    return;
+  }
+  uniforms_es3_.resize(header->num_uniforms);
+
+  uint32_t entry_size = sizeof(UniformES3Info) * header->num_uniforms;
+  DCHECK_EQ(result.size(), header_size + entry_size);
+  const UniformES3Info* entries = LocalGetAs<const UniformES3Info*>(
+      result, header_size, entry_size);
+  DCHECK(entries);
+
+  for (uint32_t ii = 0; ii < header->num_uniforms; ++ii) {
+    uniforms_es3_[ii].block_index = entries[ii].block_index;
+    uniforms_es3_[ii].offset = entries[ii].offset;
+    uniforms_es3_[ii].array_stride = entries[ii].array_stride;
+    uniforms_es3_[ii].matrix_stride = entries[ii].matrix_stride;
+    uniforms_es3_[ii].is_row_major = entries[ii].is_row_major;
+  }
+  cached_es3_uniformsiv_ = true;
+}
+
+void ProgramInfoManager::Program::UpdateES3TransformFeedbackVaryings(
+    const std::vector<int8>& result) {
+  if (cached_es3_transform_feedback_varyings_) {
+    return;
+  }
+  if (result.empty()) {
+    // This should only happen on a lost context.
+    return;
+  }
+  transform_feedback_varyings_.clear();
+  transform_feedback_varying_max_length_ = 0;
+
+  // |result| comes from GPU process. We consider it trusted data. Therefore,
+  // no need to check for overflows as the GPU side did the checks already.
+  uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader);
+  DCHECK_GE(result.size(), header_size);
+  const TransformFeedbackVaryingsHeader* header =
+      LocalGetAs<const TransformFeedbackVaryingsHeader*>(
+          result, 0, header_size);
+  DCHECK(header);
+  if (header->num_transform_feedback_varyings == 0) {
+    DCHECK_EQ(result.size(), header_size);
+    // TODO(zmo): Here we can't tell if no TransformFeedback varyings are
+    // defined, or the previous link failed.
+    return;
+  }
+  transform_feedback_varyings_.resize(header->num_transform_feedback_varyings);
+
+  uint32_t entry_size = sizeof(TransformFeedbackVaryingInfo) *
+      header->num_transform_feedback_varyings;
+  DCHECK_GE(result.size(), header_size + entry_size);
+  uint32_t data_size = result.size() - header_size - entry_size;
+  DCHECK_LT(0u, data_size);
+  const TransformFeedbackVaryingInfo* entries =
+      LocalGetAs<const TransformFeedbackVaryingInfo*>(
+          result, header_size, entry_size);
+  DCHECK(entries);
+  const char* data = LocalGetAs<const char*>(
+      result, header_size + entry_size, data_size);
+  DCHECK(data);
+
+  uint32_t size = 0;
+  for (uint32_t ii = 0; ii < header->num_transform_feedback_varyings; ++ii) {
+    transform_feedback_varyings_[ii].size =
+        static_cast<GLsizei>(entries[ii].size);
+    transform_feedback_varyings_[ii].type =
+        static_cast<GLenum>(entries[ii].type);
+    DCHECK_LE(1u, entries[ii].name_length);
+    if (entries[ii].name_length > transform_feedback_varying_max_length_) {
+      transform_feedback_varying_max_length_ = entries[ii].name_length;
+    }
+    size += entries[ii].name_length;
+    DCHECK_GE(data_size, size);
+    transform_feedback_varyings_[ii].name =
+        std::string(data, entries[ii].name_length - 1);
+    data += entries[ii].name_length;
+  }
+  DCHECK_EQ(data_size, size);
+  cached_es3_transform_feedback_varyings_ = true;
+}
+
 bool ProgramInfoManager::Program::IsCached(ProgramInfoType type) const {
   switch (type) {
     case kES2:
       return cached_es2_;
     case kES3UniformBlocks:
       return cached_es3_uniform_blocks_;
+    case kES3TransformFeedbackVaryings:
+      return cached_es3_transform_feedback_varyings_;
+    case kES3Uniformsiv:
+      return cached_es3_uniformsiv_;
     case kNone:
       return true;
     default:
@@ -354,12 +599,26 @@
         base::AutoUnlock unlock(lock_);
         // lock_ can't be held across IPC call or else it may deadlock in
         // pepper. http://crbug.com/418651
-
-        // TODO(zmo): Uncomment the below line once GetUniformBlocksCHROMIUM
-        // command is implemented.
-        // gl->GetUniformBlocksCHROMIUMHeler(program, &result);
+        gl->GetUniformBlocksCHROMIUMHelper(program, &result);
       }
       info->UpdateES3UniformBlocks(result);
+      break;
+    case kES3TransformFeedbackVaryings:
+      {
+        base::AutoUnlock unlock(lock_);
+        // lock_ can't be held across IPC call or else it may deadlock in
+        // pepper. http://crbug.com/418651
+        gl->GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
+      }
+      info->UpdateES3TransformFeedbackVaryings(result);
+    case kES3Uniformsiv:
+      {
+        base::AutoUnlock unlock(lock_);
+        // lock_ can't be held across IPC call or else it may deadlock in
+        // pepper. http://crbug.com/418651
+        gl->GetUniformsES3CHROMIUMHelper(program, &result);
+      }
+      info->UpdateES3Uniformsiv(result);
     default:
       NOTREACHED();
       return NULL;
@@ -397,6 +656,10 @@
     case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
       type = kES3UniformBlocks;
       break;
+    case GL_TRANSFORM_FEEDBACK_VARYINGS:
+    case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+      type = kES3TransformFeedbackVaryings;
+      break;
     default:
       return false;
   }
@@ -407,6 +670,34 @@
   return info->GetProgramiv(pname, params);
 }
 
+bool ProgramInfoManager::GetActiveUniformsiv(
+    GLES2Implementation* gl, GLuint program, GLsizei count,
+    const GLuint* indices, GLenum pname, GLint* params) {
+  base::AutoLock auto_lock(lock_);
+  ProgramInfoType type = kNone;
+  switch (pname) {
+    case GL_UNIFORM_SIZE:
+    case GL_UNIFORM_TYPE:
+    case GL_UNIFORM_NAME_LENGTH:
+      type = kES2;
+      break;
+    case GL_UNIFORM_BLOCK_INDEX:
+    case GL_UNIFORM_OFFSET:
+    case GL_UNIFORM_ARRAY_STRIDE:
+    case GL_UNIFORM_MATRIX_STRIDE:
+    case GL_UNIFORM_IS_ROW_MAJOR:
+      type = kES3Uniformsiv;
+      break;
+    default:
+      return false;
+  }
+  Program* info = GetProgramInfo(gl, program, type);
+  if (info) {
+    return info->GetUniformsiv(count, indices, pname, params);
+  }
+  return gl->GetActiveUniformsivHelper(program, count, indices, pname, params);
+}
+
 GLint ProgramInfoManager::GetAttribLocation(
     GLES2Implementation* gl, GLuint program, const char* name) {
   {
@@ -635,9 +926,73 @@
       }
     }
   }
-  return false;
-  // TODO(zmo): return gl->GetActiveUniformBlockivHelper(
-  //                program, index, pname, params);
+  return gl->GetActiveUniformBlockivHelper(program, index, pname, params);
+}
+
+void ProgramInfoManager::UniformBlockBinding(
+    GLES2Implementation* gl, GLuint program, GLuint index, GLuint binding) {
+  GLuint max_bindings =
+      static_cast<GLuint>(gl->capabilities().max_uniform_buffer_bindings);
+  if (binding < max_bindings) {
+    base::AutoLock auto_lock(lock_);
+    // If UniformBlock info haven't been cached yet, skip updating the binding.
+    Program* info = GetProgramInfo(gl, program, kNone);
+    if (info) {
+      info->UniformBlockBinding(index, binding);
+    }
+  }
+}
+
+bool ProgramInfoManager::GetTransformFeedbackVarying(
+    GLES2Implementation* gl, GLuint program, GLuint index, GLsizei bufsize,
+    GLsizei* length, GLsizei* size, GLenum* type, char* name) {
+  {
+    base::AutoLock auto_lock(lock_);
+    Program* info = GetProgramInfo(gl, program, kES3TransformFeedbackVaryings);
+    if (info) {
+      const Program::TransformFeedbackVarying* varying =
+          info->GetTransformFeedbackVarying(index);
+      if (varying) {
+        if (size) {
+          *size = varying->size;
+        }
+        if (type) {
+          *type = varying->type;
+        }
+        if (length || name) {
+          GLsizei max_size = std::min(
+              bufsize - 1, static_cast<GLsizei>(varying->name.size()));
+          if (length) {
+            *length = static_cast<GLsizei>(max_size);
+          }
+          if (name && bufsize > 0) {
+            memcpy(name, varying->name.c_str(), max_size);
+            name[max_size] = '\0';
+          }
+        }
+        return true;
+      }
+    }
+  }
+  return gl->GetTransformFeedbackVaryingHelper(
+      program, index, bufsize, length, size, type, name);
+}
+
+bool ProgramInfoManager::GetUniformIndices(GLES2Implementation* gl,
+    GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
+  {
+    base::AutoLock auto_lock(lock_);
+    Program* info = GetProgramInfo(gl, program, kES2);
+    if (info) {
+      DCHECK_LT(0, count);
+      DCHECK(names && indices);
+      for (GLsizei ii = 0; ii < count; ++ii) {
+        indices[ii] = info->GetUniformIndex(names[ii]);
+      }
+      return true;
+    }
+  }
+  return gl->GetUniformIndicesHelper(program, count, names, indices);
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/client/program_info_manager.h b/gpu/command_buffer/client/program_info_manager.h
index efbff73..6f8a745 100644
--- a/gpu/command_buffer/client/program_info_manager.h
+++ b/gpu/command_buffer/client/program_info_manager.h
@@ -60,14 +60,39 @@
       GLES2Implementation* gl, GLuint program, GLuint index,
       GLenum pname, GLint* params);
 
+  // Attempt to update the |index| uniform block binding.
+  // It's no op if the program does not exist, or the |index| uniform block
+  // is not in the cache, or binding >= GL_MAX_UNIFORM_BUFFER_BINDINGS.
+  void UniformBlockBinding(
+      GLES2Implementation* gl, GLuint program, GLuint index, GLuint binding);
+
+  bool GetTransformFeedbackVarying(
+      GLES2Implementation* gl, GLuint program, GLuint index, GLsizei bufsize,
+      GLsizei* length, GLsizei* size, GLenum* type, char* name);
+
+  bool GetUniformIndices(
+      GLES2Implementation* gl, GLuint program, GLsizei count,
+      const char* const* names, GLuint* indices);
+
+  bool GetActiveUniformsiv(
+      GLES2Implementation* gl, GLuint program, GLsizei count,
+      const GLuint* indices, GLenum pname, GLint* params);
+
  private:
   friend class ProgramInfoManagerTest;
 
+  FRIEND_TEST_ALL_PREFIXES(ProgramInfoManagerTest, UpdateES2);
   FRIEND_TEST_ALL_PREFIXES(ProgramInfoManagerTest, UpdateES3UniformBlocks);
+  FRIEND_TEST_ALL_PREFIXES(ProgramInfoManagerTest,
+                           UpdateES3TransformFeedbackVaryings);
+  FRIEND_TEST_ALL_PREFIXES(ProgramInfoManagerTest,
+                           GetActiveUniformsivCached);
 
   enum ProgramInfoType {
     kES2,
     kES3UniformBlocks,
+    kES3TransformFeedbackVaryings,
+    kES3Uniformsiv,
     kNone,
   };
 
@@ -84,6 +109,16 @@
       std::string name;
       std::vector<GLint> element_locations;
     };
+    struct UniformES3 {
+      UniformES3();
+      ~UniformES3();
+
+      GLint block_index;
+      GLint offset;
+      GLint array_stride;
+      GLint matrix_stride;
+      GLint is_row_major;
+    };
     struct VertexAttrib {
       VertexAttrib(GLsizei _size, GLenum _type, const std::string& _name,
                    GLint _location);
@@ -105,6 +140,14 @@
       GLboolean referenced_by_fragment_shader;
       std::string name;
     };
+    struct TransformFeedbackVarying {
+      TransformFeedbackVarying();
+      ~TransformFeedbackVarying();
+
+      GLsizei size;
+      GLenum type;
+      std::string name;
+    };
 
     Program();
     ~Program();
@@ -117,6 +160,11 @@
 
     // Gets the location of a uniform by name.
     GLint GetUniformLocation(const std::string& name) const;
+    // Gets the index of a uniform by name. Return INVALID_INDEX in failure.
+    GLuint GetUniformIndex(const std::string& name) const;
+
+    bool GetUniformsiv(
+        GLsizei count, const GLuint* indices, GLenum pname, GLint* params);
 
     GLint GetFragDataLocation(const std::string& name) const;
     void CacheFragDataLocation(const std::string& name, GLint loc);
@@ -126,6 +174,11 @@
     // Gets the index of a uniform block by name.
     GLuint GetUniformBlockIndex(const std::string& name) const;
     const UniformBlock* GetUniformBlock(GLuint index) const;
+    // Update the binding if the |index| uniform block is in the cache.
+    void UniformBlockBinding(GLuint index, GLuint binding);
+
+    const TransformFeedbackVarying* GetTransformFeedbackVarying(
+        GLuint index) const;
 
     // Updates the ES2 only program info after a successful link.
     void UpdateES2(const std::vector<int8>& result);
@@ -133,6 +186,12 @@
     // Updates the ES3 UniformBlock info after a successful link.
     void UpdateES3UniformBlocks(const std::vector<int8>& result);
 
+    // Updates the ES3 Uniformsiv info after a successful link.
+    void UpdateES3Uniformsiv(const std::vector<int8>& result);
+
+    // Updates the ES3 TransformFeedbackVaryings info after a successful link.
+    void UpdateES3TransformFeedbackVaryings(const std::vector<int8>& result);
+
     bool IsCached(ProgramInfoType type) const;
 
    private:
@@ -160,6 +219,17 @@
     // Uniform blocks by index.
     std::vector<UniformBlock> uniform_blocks_;
 
+    bool cached_es3_transform_feedback_varyings_;
+
+    uint32_t transform_feedback_varying_max_length_;
+
+    // TransformFeedback varyings by index.
+    std::vector<TransformFeedbackVarying> transform_feedback_varyings_;
+
+    bool cached_es3_uniformsiv_;
+
+    std::vector<UniformES3> uniforms_es3_;
+
     base::hash_map<std::string, GLint> frag_data_locations_;
   };
 
diff --git a/gpu/command_buffer/client/program_info_manager_unittest.cc b/gpu/command_buffer/client/program_info_manager_unittest.cc
index 6b0576c..f9c6b00 100644
--- a/gpu/command_buffer/client/program_info_manager_unittest.cc
+++ b/gpu/command_buffer/client/program_info_manager_unittest.cc
@@ -27,6 +27,16 @@
  protected:
   typedef ProgramInfoManager::Program Program;
 
+  struct ProgramES2Data {
+    // TODO(zmo): Also add attrib data.
+    ProgramInfoHeader header;
+    ProgramInput uniforms[2];
+    int32_t uniform_loc0[1];
+    int32_t uniform_loc1[2];
+    char uniform_name0[4];
+    char uniform_name1[8];
+  };
+
   struct UniformBlocksData {
     UniformBlocksHeader header;
     UniformBlockInfo entry[2];
@@ -36,6 +46,18 @@
     uint32_t indices1[1];
   };
 
+  struct UniformsES3Data {
+    UniformsES3Header header;
+    UniformES3Info entry[2];
+  };
+
+  struct TransformFeedbackVaryingsData {
+    TransformFeedbackVaryingsHeader header;
+    TransformFeedbackVaryingInfo entry[2];
+    char name0[4];
+    char name1[8];
+  };
+
   void SetUp() override {
     program_info_manager_.reset(new ProgramInfoManager);
     program_info_manager_->CreateInfo(kClientProgramId);
@@ -49,6 +71,34 @@
 
   void TearDown() override {}
 
+  void SetupProgramES2Data(ProgramES2Data* data) {
+    // The names needs to be of size 4*k-1 to avoid padding in the struct Data.
+    // This is a testing only problem.
+    const char* kName[] = { "cow", "bull[0]" };
+    data->header.link_status = 1;
+    data->header.num_attribs = 0;
+    data->header.num_uniforms = 2;
+    data->uniforms[0].type = GL_FLOAT;
+    data->uniforms[0].size = 1;
+    data->uniforms[0].location_offset =
+        ComputeOffset(data, &data->uniform_loc0);
+    data->uniforms[0].name_offset =
+        ComputeOffset(data, &data->uniform_name0);
+    data->uniforms[0].name_length = strlen(kName[0]);
+    data->uniforms[1].type = GL_FLOAT_VEC4;
+    data->uniforms[1].size = 2;
+    data->uniforms[1].location_offset =
+        ComputeOffset(data, &data->uniform_loc1);
+    data->uniforms[1].name_offset =
+        ComputeOffset(data, &data->uniform_name1);
+    data->uniforms[1].name_length = strlen(kName[1]);
+    data->uniform_loc0[0] = 1;
+    data->uniform_loc1[0] = 2;
+    data->uniform_loc1[1] = 3;
+    memcpy(data->uniform_name0, kName[0], arraysize(data->uniform_name0));
+    memcpy(data->uniform_name1, kName[1], arraysize(data->uniform_name1));
+  }
+
   void SetupUniformBlocksData(UniformBlocksData* data) {
     // The names needs to be of size 4*k-1 to avoid padding in the struct Data.
     // This is a testing only problem.
@@ -80,10 +130,87 @@
     data->indices1[0] = kIndices[1][0];
   }
 
+  void SetupUniformsES3Data(UniformsES3Data* data) {
+    data->header.num_uniforms = 2;
+    data->entry[0].block_index = 1;
+    data->entry[0].offset = 2;
+    data->entry[0].array_stride = 3;
+    data->entry[0].matrix_stride = 4;
+    data->entry[0].is_row_major = 0;
+    data->entry[1].block_index = 5;
+    data->entry[1].offset = 6;
+    data->entry[1].array_stride = 7;
+    data->entry[1].matrix_stride = 8;
+    data->entry[1].is_row_major = 1;
+  }
+
+  void SetupTransformFeedbackVaryingsData(TransformFeedbackVaryingsData* data) {
+    // The names needs to be of size 4*k-1 to avoid padding in the struct Data.
+    // This is a testing only problem.
+    const char* kName[] = { "cow", "chicken" };
+    data->header.num_transform_feedback_varyings = 2;
+    data->entry[0].size = 1;
+    data->entry[0].type = GL_FLOAT_VEC2;
+    data->entry[0].name_offset = ComputeOffset(data, data->name0);
+    data->entry[0].name_length = arraysize(data->name0);
+    data->entry[1].size = 2;
+    data->entry[1].type = GL_FLOAT;
+    data->entry[1].name_offset = ComputeOffset(data, data->name1);
+    data->entry[1].name_length = arraysize(data->name1);
+    memcpy(data->name0, kName[0], arraysize(data->name0));
+    memcpy(data->name1, kName[1], arraysize(data->name1));
+  }
+
   scoped_ptr<ProgramInfoManager> program_info_manager_;
   Program* program_;
 };
 
+TEST_F(ProgramInfoManagerTest, UpdateES2) {
+  ProgramES2Data data;
+  SetupProgramES2Data(&data);
+  const std::string kNames[] = { data.uniform_name0, data.uniform_name1 };
+  const int32_t* kLocs[] = { data.uniform_loc0, data.uniform_loc1 };
+  std::vector<int8> result(sizeof(data));
+  memcpy(&result[0], &data, sizeof(data));
+  EXPECT_FALSE(program_->IsCached(ProgramInfoManager::kES2));
+  program_->UpdateES2(result);
+  EXPECT_TRUE(program_->IsCached(ProgramInfoManager::kES2));
+
+  GLint params = 0;
+  EXPECT_TRUE(program_->GetProgramiv(GL_LINK_STATUS, &params));
+  EXPECT_TRUE(params);
+
+  params = 0;
+  EXPECT_TRUE(program_->GetProgramiv(GL_ACTIVE_ATTRIBUTES, &params));
+  EXPECT_EQ(data.header.num_attribs, static_cast<uint32_t>(params));
+  params = 0;
+  EXPECT_TRUE(program_->GetProgramiv(GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &params));
+  EXPECT_EQ(0, params);
+
+  params = 0;
+  EXPECT_TRUE(program_->GetProgramiv(GL_ACTIVE_UNIFORMS, &params));
+  EXPECT_EQ(data.header.num_uniforms, static_cast<uint32_t>(params));
+  GLint active_uniform_max_length = 0;
+  EXPECT_TRUE(program_->GetProgramiv(
+      GL_ACTIVE_UNIFORM_MAX_LENGTH, &active_uniform_max_length));
+
+  for (uint32_t ii = 0; ii < data.header.num_uniforms; ++ii) {
+    const Program::UniformInfo* info = program_->GetUniformInfo(ii);
+    EXPECT_TRUE(info != NULL);
+    EXPECT_EQ(data.uniforms[ii].type, info->type);
+    EXPECT_EQ(data.uniforms[ii].size, info->size);
+    EXPECT_LT(kNames[0].length(),
+              static_cast<size_t>(active_uniform_max_length));
+    EXPECT_EQ(kNames[ii], info->name);
+    EXPECT_EQ(kNames[ii][kNames[ii].length() - 1] == ']', info->is_array);
+    EXPECT_EQ(data.uniforms[ii].size,
+              static_cast<int32_t>(info->element_locations.size()));
+    for (int32_t uu = 0; uu < data.uniforms[ii].size; ++uu) {
+      EXPECT_EQ(kLocs[ii][uu], info->element_locations[uu]);
+    }
+  }
+}
+
 TEST_F(ProgramInfoManagerTest, UpdateES3UniformBlocks) {
   UniformBlocksData data;
   SetupUniformBlocksData(&data);
@@ -126,6 +253,40 @@
   EXPECT_EQ(NULL, program_->GetUniformBlock(data.header.num_uniform_blocks));
 }
 
+TEST_F(ProgramInfoManagerTest, UpdateES3TransformFeedbackVaryings) {
+  TransformFeedbackVaryingsData data;
+  SetupTransformFeedbackVaryingsData(&data);
+  const std::string kName[] = { data.name0, data.name1 };
+  std::vector<int8> result(sizeof(data));
+  memcpy(&result[0], &data, sizeof(data));
+  EXPECT_FALSE(program_->IsCached(
+      ProgramInfoManager::kES3TransformFeedbackVaryings));
+  program_->UpdateES3TransformFeedbackVaryings(result);
+  EXPECT_TRUE(program_->IsCached(
+      ProgramInfoManager::kES3TransformFeedbackVaryings));
+
+  GLint transform_feedback_varying_count = 0;
+  EXPECT_TRUE(program_->GetProgramiv(
+      GL_TRANSFORM_FEEDBACK_VARYINGS, &transform_feedback_varying_count));
+  EXPECT_EQ(data.header.num_transform_feedback_varyings,
+            static_cast<uint32_t>(transform_feedback_varying_count));
+  GLint max_name_length = 0;
+  EXPECT_TRUE(program_->GetProgramiv(
+      GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &max_name_length));
+  for (uint32_t ii = 0; ii < data.header.num_transform_feedback_varyings;
+       ++ii) {
+    const Program::TransformFeedbackVarying* varying =
+        program_->GetTransformFeedbackVarying(ii);
+    EXPECT_TRUE(varying != NULL);
+    EXPECT_EQ(data.entry[ii].size, static_cast<uint32_t>(varying->size));
+    EXPECT_EQ(data.entry[ii].type, varying->type);
+    EXPECT_EQ(kName[ii], varying->name);
+    EXPECT_GE(max_name_length, static_cast<GLint>(varying->name.size()) + 1);
+  }
+  EXPECT_EQ(NULL, program_->GetTransformFeedbackVarying(
+  data.header.num_transform_feedback_varyings));
+}
+
 TEST_F(ProgramInfoManagerTest, GetUniformBlockIndexCached) {
   UniformBlocksData data;
   SetupUniformBlocksData(&data);
@@ -179,6 +340,210 @@
   EXPECT_STREQ(std::string(data.name0).substr(0, length).c_str(), &buffer[0]);
 }
 
+TEST_F(ProgramInfoManagerTest, GetActiveUniformBlockivCached) {
+  UniformBlocksData data;
+  SetupUniformBlocksData(&data);
+  std::vector<int8> result(sizeof(data));
+  memcpy(&result[0], &data, sizeof(data));
+  program_->UpdateES3UniformBlocks(result);
+  const char* kName[] = { data.name0, data.name1 };
+  const uint32_t* kIndices[] = { data.indices0, data.indices1 };
+
+  for (uint32_t ii = 0; ii < data.header.num_uniform_blocks; ++ii) {
+    ASSERT_GE(2u, data.entry[ii].active_uniforms);
+    GLint params[2];
+    EXPECT_TRUE(program_info_manager_->GetActiveUniformBlockiv(
+        NULL, kClientProgramId, ii, GL_UNIFORM_BLOCK_BINDING, params));
+    EXPECT_EQ(data.entry[ii].binding, static_cast<uint32_t>(params[0]));
+
+    EXPECT_TRUE(program_info_manager_->GetActiveUniformBlockiv(
+        NULL, kClientProgramId, ii, GL_UNIFORM_BLOCK_DATA_SIZE, params));
+    EXPECT_EQ(data.entry[ii].data_size, static_cast<uint32_t>(params[0]));
+
+    EXPECT_TRUE(program_info_manager_->GetActiveUniformBlockiv(
+        NULL, kClientProgramId, ii, GL_UNIFORM_BLOCK_NAME_LENGTH, params));
+    EXPECT_EQ(strlen(kName[ii]) + 1, static_cast<uint32_t>(params[0]));
+
+    EXPECT_TRUE(program_info_manager_->GetActiveUniformBlockiv(
+        NULL, kClientProgramId, ii, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, params));
+    EXPECT_EQ(data.entry[ii].active_uniforms, static_cast<uint32_t>(params[0]));
+
+    EXPECT_TRUE(program_info_manager_->GetActiveUniformBlockiv(
+        NULL, kClientProgramId, ii,
+        GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, params));
+    for (uint32_t uu = 0; uu < data.entry[ii].active_uniforms; ++uu) {
+      EXPECT_EQ(kIndices[ii][uu], static_cast<uint32_t>(params[uu]));
+    }
+
+    EXPECT_TRUE(program_info_manager_->GetActiveUniformBlockiv(
+        NULL, kClientProgramId, ii,
+        GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, params));
+    EXPECT_EQ(data.entry[ii].referenced_by_vertex_shader,
+              static_cast<uint32_t>(params[0]));
+
+    EXPECT_TRUE(program_info_manager_->GetActiveUniformBlockiv(
+        NULL, kClientProgramId, ii,
+        GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, params));
+    EXPECT_EQ(data.entry[ii].referenced_by_fragment_shader,
+              static_cast<uint32_t>(params[0]));
+  }
+}
+
+TEST_F(ProgramInfoManagerTest, GetTransformFeedbackVaryingCached) {
+  TransformFeedbackVaryingsData data;
+  SetupTransformFeedbackVaryingsData(&data);
+  std::vector<int8> result(sizeof(data));
+  memcpy(&result[0], &data, sizeof(data));
+  program_->UpdateES3TransformFeedbackVaryings(result);
+  const char* kName[] = { data.name0, data.name1 };
+  GLsizei buf_size = std::max(strlen(kName[0]), strlen(kName[1])) + 1;
+  for (uint32_t ii = 0; ii < data.header.num_transform_feedback_varyings;
+       ++ii) {
+    std::vector<char> buffer(buf_size);
+    GLsizei length = 0;
+    GLsizei size = 0;
+    GLenum type = 0;
+    EXPECT_EQ(true, program_info_manager_->GetTransformFeedbackVarying(
+        NULL, kClientProgramId, ii, buf_size,
+        &length, &size, &type, &buffer[0]));
+    EXPECT_EQ(data.entry[ii].size, static_cast<uint32_t>(size));
+    EXPECT_EQ(data.entry[ii].type, static_cast<uint32_t>(type));
+    EXPECT_STREQ(kName[ii], &buffer[0]);
+    EXPECT_EQ(strlen(kName[ii]), static_cast<size_t>(length));
+  }
+}
+
+TEST_F(ProgramInfoManagerTest, GetUniformIndices) {
+  ProgramES2Data data;
+  SetupProgramES2Data(&data);
+  std::vector<int8> result(sizeof(data));
+  memcpy(&result[0], &data, sizeof(data));
+  program_->UpdateES2(result);
+
+  {  // Original order.
+    const char* kNames[] = { data.uniform_name0, data.uniform_name1 };
+    const GLuint kIndices[] = { 0, 1 };
+    const GLsizei kCount = 2;
+    GLuint indices[kCount];
+    EXPECT_TRUE(program_info_manager_->GetUniformIndices(
+        NULL, kClientProgramId, kCount, kNames, indices));
+    for (GLsizei ii = 0; ii < kCount; ++ii) {
+      EXPECT_EQ(kIndices[ii], indices[ii]);
+    }
+  }
+
+  {  // Switched order.
+    const char* kNames[] = { data.uniform_name1, data.uniform_name0 };
+    const GLuint kIndices[] = { 1, 0 };
+    const GLsizei kCount = 2;
+    GLuint indices[kCount];
+    EXPECT_TRUE(program_info_manager_->GetUniformIndices(
+        NULL, kClientProgramId, kCount, kNames, indices));
+    for (GLsizei ii = 0; ii < kCount; ++ii) {
+      EXPECT_EQ(kIndices[ii], indices[ii]);
+    }
+  }
+
+  {  // With bad names.
+    const char* kNames[] = { data.uniform_name1, "BadName" };
+    const GLuint kIndices[] = { 1, GL_INVALID_INDEX };
+    const GLsizei kCount = 2;
+    GLuint indices[kCount];
+    EXPECT_TRUE(program_info_manager_->GetUniformIndices(
+        NULL, kClientProgramId, kCount, kNames, indices));
+    for (GLsizei ii = 0; ii < kCount; ++ii) {
+      EXPECT_EQ(kIndices[ii], indices[ii]);
+    }
+  }
+
+  {  // Both "foo" and "foo[0]" are considered valid names for an array,
+     // but not "foo[1]".
+    const char* kNames[] = { "bull", "bull[0]", "bull[1]" };
+    const GLuint kIndices[] = { 1, 1, GL_INVALID_INDEX };
+    const GLsizei kCount = 3;
+    GLuint indices[kCount];
+    EXPECT_TRUE(program_info_manager_->GetUniformIndices(
+        NULL, kClientProgramId, kCount, kNames, indices));
+    for (GLsizei ii = 0; ii < kCount; ++ii) {
+      EXPECT_EQ(kIndices[ii], indices[ii]);
+    }
+  }
+}
+
+TEST_F(ProgramInfoManagerTest, GetActiveUniformsivCached) {
+  // ES3 only parameters.
+  UniformsES3Data data_es3;
+  SetupUniformsES3Data(&data_es3);
+  std::vector<int8> result(sizeof(data_es3));
+  memcpy(&result[0], &data_es3, sizeof(data_es3));
+  EXPECT_FALSE(program_->IsCached(ProgramInfoManager::kES3Uniformsiv));
+  program_->UpdateES3Uniformsiv(result);
+  EXPECT_TRUE(program_->IsCached(ProgramInfoManager::kES3Uniformsiv));
+
+  uint32_t count = data_es3.header.num_uniforms;
+  std::vector<GLuint> indices(count);
+  for (uint32_t ii = 0; ii < count; ++ii) {
+    indices[ii] = ii;
+  }
+  std::vector<GLint> block_index(count);
+  EXPECT_TRUE(program_info_manager_->GetActiveUniformsiv(
+      NULL, kClientProgramId, static_cast<GLsizei>(count), &indices[0],
+      GL_UNIFORM_BLOCK_INDEX, &block_index[0]));
+  std::vector<GLint> offset(count);
+  EXPECT_TRUE(program_info_manager_->GetActiveUniformsiv(
+      NULL, kClientProgramId, static_cast<GLsizei>(count), &indices[0],
+      GL_UNIFORM_OFFSET, &offset[0]));
+  std::vector<GLint> array_stride(count);
+  EXPECT_TRUE(program_info_manager_->GetActiveUniformsiv(
+      NULL, kClientProgramId, static_cast<GLsizei>(count), &indices[0],
+      GL_UNIFORM_ARRAY_STRIDE, &array_stride[0]));
+  std::vector<GLint> matrix_stride(count);
+  EXPECT_TRUE(program_info_manager_->GetActiveUniformsiv(
+      NULL, kClientProgramId, static_cast<GLsizei>(count), &indices[0],
+      GL_UNIFORM_MATRIX_STRIDE, &matrix_stride[0]));
+  std::vector<GLint> is_row_major(count);
+  EXPECT_TRUE(program_info_manager_->GetActiveUniformsiv(
+      NULL, kClientProgramId, static_cast<GLsizei>(count), &indices[0],
+      GL_UNIFORM_IS_ROW_MAJOR, &is_row_major[0]));
+
+  for (uint32_t ii = 0; ii < count; ++ii) {
+    EXPECT_EQ(data_es3.entry[ii].block_index, block_index[ii]);
+    EXPECT_EQ(data_es3.entry[ii].offset, offset[ii]);
+    EXPECT_EQ(data_es3.entry[ii].array_stride, array_stride[ii]);
+    EXPECT_EQ(data_es3.entry[ii].matrix_stride, matrix_stride[ii]);
+    EXPECT_EQ(data_es3.entry[ii].is_row_major, is_row_major[ii]);
+  }
+
+  // ES2 parameters.
+  ProgramES2Data data_es2;
+  SetupProgramES2Data(&data_es2);
+  result.resize(sizeof(data_es2));
+  memcpy(&result[0], &data_es2, sizeof(data_es2));
+  EXPECT_FALSE(program_->IsCached(ProgramInfoManager::kES2));
+  program_->UpdateES2(result);
+  EXPECT_TRUE(program_->IsCached(ProgramInfoManager::kES2));
+
+  std::vector<GLint> size(count);
+  EXPECT_TRUE(program_info_manager_->GetActiveUniformsiv(
+      NULL, kClientProgramId, static_cast<GLsizei>(count), &indices[0],
+      GL_UNIFORM_SIZE, &size[0]));
+  std::vector<GLint> type(count);
+  EXPECT_TRUE(program_info_manager_->GetActiveUniformsiv(
+      NULL, kClientProgramId, static_cast<GLsizei>(count), &indices[0],
+      GL_UNIFORM_TYPE, &type[0]));
+  std::vector<GLint> name_length(count);
+  EXPECT_TRUE(program_info_manager_->GetActiveUniformsiv(
+      NULL, kClientProgramId, static_cast<GLsizei>(count), &indices[0],
+      GL_UNIFORM_NAME_LENGTH, &name_length[0]));
+
+  for (uint32_t ii = 0; ii < count; ++ii) {
+    EXPECT_EQ(data_es2.uniforms[ii].size, size[ii]);
+    EXPECT_EQ(data_es2.uniforms[ii].type, static_cast<uint32_t>(type[ii]));
+    EXPECT_EQ(data_es2.uniforms[ii].name_length + 1,
+              static_cast<uint32_t>(name_length[ii]));
+  }
+}
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index c415e48..3e8d902 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -77,7 +77,9 @@
 GL_APICALL void         GL_APIENTRY glGenTransformFeedbacks (GLsizeiNotNegative n, GLuint* ids);
 GL_APICALL void         GL_APIENTRY glGetActiveAttrib (GLidProgram program, GLuint index, GLsizeiNotNegative bufsize, GLsizeiOptional* length, GLint* size, GLenum* type, char* name);
 GL_APICALL void         GL_APIENTRY glGetActiveUniform (GLidProgram program, GLuint index, GLsizeiNotNegative bufsize, GLsizeiOptional* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void         GL_APIENTRY glGetActiveUniformBlockiv (GLidProgram program, GLuint index, GLenumUniformBlockParameter pname, GLint* params);
 GL_APICALL void         GL_APIENTRY glGetActiveUniformBlockName (GLidProgram program, GLuint index, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* name);
+GL_APICALL void         GL_APIENTRY glGetActiveUniformsiv (GLidProgram program, GLsizeiNotNegative count, const GLuint* indices, GLenumUniformParameter pname, GLint* params);
 GL_APICALL void         GL_APIENTRY glGetAttachedShaders (GLidProgram program, GLsizeiNotNegative maxcount, GLsizeiOptional* count, GLuint* shaders);
 GL_APICALL GLint        GL_APIENTRY glGetAttribLocation (GLidProgram program, const char* name);
 GL_APICALL void         GL_APIENTRY glGetBooleanv (GLenumGLState pname, GLboolean* params);
@@ -100,9 +102,11 @@
 GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenumStringType name);
 GL_APICALL void         GL_APIENTRY glGetTexParameterfv (GLenumGetTexParamTarget target, GLenumTextureParameter pname, GLfloat* params);
 GL_APICALL void         GL_APIENTRY glGetTexParameteriv (GLenumGetTexParamTarget target, GLenumTextureParameter pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetTransformFeedbackVarying (GLidProgram program, GLuint index, GLsizeiNotNegative bufsize, GLsizeiOptional* length, GLsizei* size, GLenum* type, char* name);
 GL_APICALL GLuint       GL_APIENTRY glGetUniformBlockIndex (GLidProgram program, const char* name);
 GL_APICALL void         GL_APIENTRY glGetUniformfv (GLidProgram program, GLintUniformLocation location, GLfloat* params);
 GL_APICALL void         GL_APIENTRY glGetUniformiv (GLidProgram program, GLintUniformLocation location, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetUniformIndices (GLidProgram program, GLsizeiNotNegative count, const char* const* names, GLuint* indices);
 GL_APICALL GLint        GL_APIENTRY glGetUniformLocation (GLidProgram program, const char* name);
 GL_APICALL void         GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenumVertexAttribute pname, GLfloat* params);
 GL_APICALL void         GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenumVertexAttribute pname, GLint* params);
@@ -181,6 +185,7 @@
 GL_APICALL void         GL_APIENTRY glUniform4iv (GLintUniformLocation location, GLsizeiNotNegative count, const GLint* v);
 GL_APICALL void         GL_APIENTRY glUniform4ui (GLintUniformLocation location, GLuint x, GLuint y, GLuint z, GLuint w);
 GL_APICALL void         GL_APIENTRY glUniform4uiv (GLintUniformLocation location, GLsizeiNotNegative count, const GLuint* v);
+GL_APICALL void         GL_APIENTRY glUniformBlockBinding (GLidProgram program, GLuint index, GLuint binding);
 GL_APICALL void         GL_APIENTRY glUniformMatrix2fv (GLintUniformLocation location, GLsizeiNotNegative count, GLbooleanFalseOnly transpose, const GLfloat* value);
 GL_APICALL void         GL_APIENTRY glUniformMatrix2x3fv (GLintUniformLocation location, GLsizeiNotNegative count, GLbooleanFalseOnly transpose, const GLfloat* value);
 GL_APICALL void         GL_APIENTRY glUniformMatrix2x4fv (GLintUniformLocation location, GLsizeiNotNegative count, GLbooleanFalseOnly transpose, const GLfloat* value);
@@ -246,6 +251,8 @@
 GL_APICALL void         GL_APIENTRY glRateLimitOffscreenContextCHROMIUM (void);
 GL_APICALL void         GL_APIENTRY glGetProgramInfoCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
 GL_APICALL void         GL_APIENTRY glGetUniformBlocksCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
+GL_APICALL void         GL_APIENTRY glGetTransformFeedbackVaryingsCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
+GL_APICALL void         GL_APIENTRY glGetUniformsES3CHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
 GL_APICALL GLuint       GL_APIENTRY glCreateStreamTextureCHROMIUM (GLuint texture);
 GL_APICALL GLuint       GL_APIENTRY glCreateImageCHROMIUM (ClientBuffer buffer, GLsizei width, GLsizei height, GLenum internalformat);
 GL_APICALL void         GL_APIENTRY glDestroyImageCHROMIUM (GLuint image_id);
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index e4d38f0..944edfd 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -155,7 +155,7 @@
   uint32_t binding;  // UNIFORM_BLOCK_BINDING
   uint32_t data_size;  // UNIFORM_BLOCK_DATA_SIZE
   uint32_t name_offset;  // offset from UniformBlocksHeader to start of name.
-  uint32_t name_length;  // UNIFORM_BLOCK_BLOCK_NAME_LENGTH
+  uint32_t name_length;  // UNIFORM_BLOCK_NAME_LENGTH
   uint32_t active_uniforms;  // UNIFORM_BLOCK_ACTIVE_UNIFORMS
   // offset from UniformBlocksHeader to |active_uniforms| indices.
   uint32_t active_uniform_offset;
@@ -171,6 +171,37 @@
   // UniformBlockInfo uniform_blocks[num_uniform_blocks];
 };
 
+// The data for one TransformFeedbackVarying from
+// GetTransformFeedbackVaringCHROMIUM.
+struct TransformFeedbackVaryingInfo {
+  uint32_t size;
+  uint32_t type;
+  uint32_t name_offset;  // offset from Header to start of name.
+  uint32_t name_length;  // including the null terminator.
+};
+
+// The format of the bucket filled out by GetTransformFeedbackVaryingsCHROMIUM
+struct TransformFeedbackVaryingsHeader {
+  uint32_t num_transform_feedback_varyings;
+  // TransformFeedbackVaryingInfo varyings[num_transform_feedback_varyings];
+};
+
+// Parameters of a uniform that can be queried through glGetActiveUniformsiv,
+// but not through glGetActiveUniform.
+struct UniformES3Info {
+  int32_t block_index;
+  int32_t offset;
+  int32_t array_stride;
+  int32_t matrix_stride;
+  int32_t is_row_major;
+};
+
+// The format of the bucket filled out by GetUniformsivES3CHROMIUM
+struct UniformsES3Header {
+  uint32_t num_uniforms;
+  // UniformES3Info uniforms[num_uniforms];
+};
+
 // The format of QuerySync used by EXT_occlusion_query_boolean
 struct QuerySync {
   void Reset() {
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index 12b90c9..cb88581 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -3374,6 +3374,68 @@
               "offset of GetActiveUniform Result type should be "
               "8");
 
+struct GetActiveUniformBlockiv {
+  typedef GetActiveUniformBlockiv ValueType;
+  static const CommandId kCmdId = kGetActiveUniformBlockiv;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef SizedResult<GLint> Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _program,
+            GLuint _index,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    SetHeader();
+    program = _program;
+    index = _index;
+    pname = _pname;
+    params_shm_id = _params_shm_id;
+    params_shm_offset = _params_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _program,
+            GLuint _index,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_program, _index, _pname, _params_shm_id, _params_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t index;
+  uint32_t pname;
+  uint32_t params_shm_id;
+  uint32_t params_shm_offset;
+};
+
+static_assert(sizeof(GetActiveUniformBlockiv) == 24,
+              "size of GetActiveUniformBlockiv should be 24");
+static_assert(offsetof(GetActiveUniformBlockiv, header) == 0,
+              "offset of GetActiveUniformBlockiv header should be 0");
+static_assert(offsetof(GetActiveUniformBlockiv, program) == 4,
+              "offset of GetActiveUniformBlockiv program should be 4");
+static_assert(offsetof(GetActiveUniformBlockiv, index) == 8,
+              "offset of GetActiveUniformBlockiv index should be 8");
+static_assert(offsetof(GetActiveUniformBlockiv, pname) == 12,
+              "offset of GetActiveUniformBlockiv pname should be 12");
+static_assert(offsetof(GetActiveUniformBlockiv, params_shm_id) == 16,
+              "offset of GetActiveUniformBlockiv params_shm_id should be 16");
+static_assert(
+    offsetof(GetActiveUniformBlockiv, params_shm_offset) == 20,
+    "offset of GetActiveUniformBlockiv params_shm_offset should be 20");
+
 struct GetActiveUniformBlockName {
   typedef GetActiveUniformBlockName ValueType;
   static const CommandId kCmdId = kGetActiveUniformBlockName;
@@ -3437,6 +3499,67 @@
     offsetof(GetActiveUniformBlockName, result_shm_offset) == 20,
     "offset of GetActiveUniformBlockName result_shm_offset should be 20");
 
+struct GetActiveUniformsiv {
+  typedef GetActiveUniformsiv ValueType;
+  static const CommandId kCmdId = kGetActiveUniformsiv;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef SizedResult<GLint> Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _program,
+            uint32_t _indices_bucket_id,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    SetHeader();
+    program = _program;
+    indices_bucket_id = _indices_bucket_id;
+    pname = _pname;
+    params_shm_id = _params_shm_id;
+    params_shm_offset = _params_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _program,
+            uint32_t _indices_bucket_id,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_program, _indices_bucket_id, _pname,
+                                       _params_shm_id, _params_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t indices_bucket_id;
+  uint32_t pname;
+  uint32_t params_shm_id;
+  uint32_t params_shm_offset;
+};
+
+static_assert(sizeof(GetActiveUniformsiv) == 24,
+              "size of GetActiveUniformsiv should be 24");
+static_assert(offsetof(GetActiveUniformsiv, header) == 0,
+              "offset of GetActiveUniformsiv header should be 0");
+static_assert(offsetof(GetActiveUniformsiv, program) == 4,
+              "offset of GetActiveUniformsiv program should be 4");
+static_assert(offsetof(GetActiveUniformsiv, indices_bucket_id) == 8,
+              "offset of GetActiveUniformsiv indices_bucket_id should be 8");
+static_assert(offsetof(GetActiveUniformsiv, pname) == 12,
+              "offset of GetActiveUniformsiv pname should be 12");
+static_assert(offsetof(GetActiveUniformsiv, params_shm_id) == 16,
+              "offset of GetActiveUniformsiv params_shm_id should be 16");
+static_assert(offsetof(GetActiveUniformsiv, params_shm_offset) == 20,
+              "offset of GetActiveUniformsiv params_shm_offset should be 20");
+
 struct GetAttachedShaders {
   typedef GetAttachedShaders ValueType;
   static const CommandId kCmdId = kGetAttachedShaders;
@@ -4579,6 +4702,83 @@
 static_assert(offsetof(GetTexParameteriv, params_shm_offset) == 16,
               "offset of GetTexParameteriv params_shm_offset should be 16");
 
+struct GetTransformFeedbackVarying {
+  typedef GetTransformFeedbackVarying ValueType;
+  static const CommandId kCmdId = kGetTransformFeedbackVarying;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  struct Result {
+    int32_t success;
+    int32_t size;
+    uint32_t type;
+  };
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _program,
+            GLuint _index,
+            uint32_t _name_bucket_id,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    SetHeader();
+    program = _program;
+    index = _index;
+    name_bucket_id = _name_bucket_id;
+    result_shm_id = _result_shm_id;
+    result_shm_offset = _result_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _program,
+            GLuint _index,
+            uint32_t _name_bucket_id,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_program, _index, _name_bucket_id,
+                                       _result_shm_id, _result_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t index;
+  uint32_t name_bucket_id;
+  uint32_t result_shm_id;
+  uint32_t result_shm_offset;
+};
+
+static_assert(sizeof(GetTransformFeedbackVarying) == 24,
+              "size of GetTransformFeedbackVarying should be 24");
+static_assert(offsetof(GetTransformFeedbackVarying, header) == 0,
+              "offset of GetTransformFeedbackVarying header should be 0");
+static_assert(offsetof(GetTransformFeedbackVarying, program) == 4,
+              "offset of GetTransformFeedbackVarying program should be 4");
+static_assert(offsetof(GetTransformFeedbackVarying, index) == 8,
+              "offset of GetTransformFeedbackVarying index should be 8");
+static_assert(
+    offsetof(GetTransformFeedbackVarying, name_bucket_id) == 12,
+    "offset of GetTransformFeedbackVarying name_bucket_id should be 12");
+static_assert(
+    offsetof(GetTransformFeedbackVarying, result_shm_id) == 16,
+    "offset of GetTransformFeedbackVarying result_shm_id should be 16");
+static_assert(
+    offsetof(GetTransformFeedbackVarying, result_shm_offset) == 20,
+    "offset of GetTransformFeedbackVarying result_shm_offset should be 20");
+static_assert(offsetof(GetTransformFeedbackVarying::Result, success) == 0,
+              "offset of GetTransformFeedbackVarying Result success should be "
+              "0");
+static_assert(offsetof(GetTransformFeedbackVarying::Result, size) == 4,
+              "offset of GetTransformFeedbackVarying Result size should be "
+              "4");
+static_assert(offsetof(GetTransformFeedbackVarying::Result, type) == 8,
+              "offset of GetTransformFeedbackVarying Result type should be "
+              "8");
+
 struct GetUniformBlockIndex {
   typedef GetUniformBlockIndex ValueType;
   static const CommandId kCmdId = kGetUniformBlockIndex;
@@ -4742,6 +4942,61 @@
 static_assert(offsetof(GetUniformiv, params_shm_offset) == 16,
               "offset of GetUniformiv params_shm_offset should be 16");
 
+struct GetUniformIndices {
+  typedef GetUniformIndices ValueType;
+  static const CommandId kCmdId = kGetUniformIndices;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef SizedResult<GLuint> Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _program,
+            uint32_t _names_bucket_id,
+            uint32_t _indices_shm_id,
+            uint32_t _indices_shm_offset) {
+    SetHeader();
+    program = _program;
+    names_bucket_id = _names_bucket_id;
+    indices_shm_id = _indices_shm_id;
+    indices_shm_offset = _indices_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _program,
+            uint32_t _names_bucket_id,
+            uint32_t _indices_shm_id,
+            uint32_t _indices_shm_offset) {
+    static_cast<ValueType*>(cmd)->Init(_program, _names_bucket_id,
+                                       _indices_shm_id, _indices_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t names_bucket_id;
+  uint32_t indices_shm_id;
+  uint32_t indices_shm_offset;
+};
+
+static_assert(sizeof(GetUniformIndices) == 20,
+              "size of GetUniformIndices should be 20");
+static_assert(offsetof(GetUniformIndices, header) == 0,
+              "offset of GetUniformIndices header should be 0");
+static_assert(offsetof(GetUniformIndices, program) == 4,
+              "offset of GetUniformIndices program should be 4");
+static_assert(offsetof(GetUniformIndices, names_bucket_id) == 8,
+              "offset of GetUniformIndices names_bucket_id should be 8");
+static_assert(offsetof(GetUniformIndices, indices_shm_id) == 12,
+              "offset of GetUniformIndices indices_shm_id should be 12");
+static_assert(offsetof(GetUniformIndices, indices_shm_offset) == 16,
+              "offset of GetUniformIndices indices_shm_offset should be 16");
+
 struct GetUniformLocation {
   typedef GetUniformLocation ValueType;
   static const CommandId kCmdId = kGetUniformLocation;
@@ -8323,6 +8578,47 @@
 static_assert(offsetof(Uniform4uivImmediate, count) == 8,
               "offset of Uniform4uivImmediate count should be 8");
 
+struct UniformBlockBinding {
+  typedef UniformBlockBinding ValueType;
+  static const CommandId kCmdId = kUniformBlockBinding;
+  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(GLuint _program, GLuint _index, GLuint _binding) {
+    SetHeader();
+    program = _program;
+    index = _index;
+    binding = _binding;
+  }
+
+  void* Set(void* cmd, GLuint _program, GLuint _index, GLuint _binding) {
+    static_cast<ValueType*>(cmd)->Init(_program, _index, _binding);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t index;
+  uint32_t binding;
+};
+
+static_assert(sizeof(UniformBlockBinding) == 16,
+              "size of UniformBlockBinding should be 16");
+static_assert(offsetof(UniformBlockBinding, header) == 0,
+              "offset of UniformBlockBinding header should be 0");
+static_assert(offsetof(UniformBlockBinding, program) == 4,
+              "offset of UniformBlockBinding program should be 4");
+static_assert(offsetof(UniformBlockBinding, index) == 8,
+              "offset of UniformBlockBinding index should be 8");
+static_assert(offsetof(UniformBlockBinding, binding) == 12,
+              "offset of UniformBlockBinding binding should be 12");
+
 struct UniformMatrix2fvImmediate {
   typedef UniformMatrix2fvImmediate ValueType;
   static const CommandId kCmdId = kUniformMatrix2fvImmediate;
@@ -10669,6 +10965,87 @@
 static_assert(offsetof(GetUniformBlocksCHROMIUM, bucket_id) == 8,
               "offset of GetUniformBlocksCHROMIUM bucket_id should be 8");
 
+struct GetTransformFeedbackVaryingsCHROMIUM {
+  typedef GetTransformFeedbackVaryingsCHROMIUM ValueType;
+  static const CommandId kCmdId = kGetTransformFeedbackVaryingsCHROMIUM;
+  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 _program, uint32_t _bucket_id) {
+    SetHeader();
+    program = _program;
+    bucket_id = _bucket_id;
+  }
+
+  void* Set(void* cmd, GLuint _program, uint32_t _bucket_id) {
+    static_cast<ValueType*>(cmd)->Init(_program, _bucket_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t bucket_id;
+};
+
+static_assert(sizeof(GetTransformFeedbackVaryingsCHROMIUM) == 12,
+              "size of GetTransformFeedbackVaryingsCHROMIUM should be 12");
+static_assert(
+    offsetof(GetTransformFeedbackVaryingsCHROMIUM, header) == 0,
+    "offset of GetTransformFeedbackVaryingsCHROMIUM header should be 0");
+static_assert(
+    offsetof(GetTransformFeedbackVaryingsCHROMIUM, program) == 4,
+    "offset of GetTransformFeedbackVaryingsCHROMIUM program should be 4");
+static_assert(
+    offsetof(GetTransformFeedbackVaryingsCHROMIUM, bucket_id) == 8,
+    "offset of GetTransformFeedbackVaryingsCHROMIUM bucket_id should be 8");
+
+struct GetUniformsES3CHROMIUM {
+  typedef GetUniformsES3CHROMIUM ValueType;
+  static const CommandId kCmdId = kGetUniformsES3CHROMIUM;
+  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 _program, uint32_t _bucket_id) {
+    SetHeader();
+    program = _program;
+    bucket_id = _bucket_id;
+  }
+
+  void* Set(void* cmd, GLuint _program, uint32_t _bucket_id) {
+    static_cast<ValueType*>(cmd)->Init(_program, _bucket_id);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t program;
+  uint32_t bucket_id;
+};
+
+static_assert(sizeof(GetUniformsES3CHROMIUM) == 12,
+              "size of GetUniformsES3CHROMIUM should be 12");
+static_assert(offsetof(GetUniformsES3CHROMIUM, header) == 0,
+              "offset of GetUniformsES3CHROMIUM header should be 0");
+static_assert(offsetof(GetUniformsES3CHROMIUM, program) == 4,
+              "offset of GetUniformsES3CHROMIUM program should be 4");
+static_assert(offsetof(GetUniformsES3CHROMIUM, bucket_id) == 8,
+              "offset of GetUniformsES3CHROMIUM bucket_id should be 8");
+
 struct GetTranslatedShaderSourceANGLE {
   typedef GetTranslatedShaderSourceANGLE ValueType;
   static const CommandId kCmdId = kGetTranslatedShaderSourceANGLE;
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 5174384..a89683a 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -1095,6 +1095,24 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, GetActiveUniformBlockiv) {
+  cmds::GetActiveUniformBlockiv& cmd =
+      *GetBufferAs<cmds::GetActiveUniformBlockiv>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12),
+              static_cast<GLenum>(13), static_cast<uint32_t>(14),
+              static_cast<uint32_t>(15));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetActiveUniformBlockiv::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.index);
+  EXPECT_EQ(static_cast<GLenum>(13), cmd.pname);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.params_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(15), cmd.params_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, GetActiveUniformBlockName) {
   cmds::GetActiveUniformBlockName& cmd =
       *GetBufferAs<cmds::GetActiveUniformBlockName>();
@@ -1113,6 +1131,23 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, GetActiveUniformsiv) {
+  cmds::GetActiveUniformsiv& cmd = *GetBufferAs<cmds::GetActiveUniformsiv>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12),
+              static_cast<GLenum>(13), static_cast<uint32_t>(14),
+              static_cast<uint32_t>(15));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetActiveUniformsiv::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.indices_bucket_id);
+  EXPECT_EQ(static_cast<GLenum>(13), cmd.pname);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.params_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(15), cmd.params_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, GetAttachedShaders) {
   cmds::GetAttachedShaders& cmd = *GetBufferAs<cmds::GetAttachedShaders>();
   void* next_cmd =
@@ -1433,6 +1468,24 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, GetTransformFeedbackVarying) {
+  cmds::GetTransformFeedbackVarying& cmd =
+      *GetBufferAs<cmds::GetTransformFeedbackVarying>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12),
+              static_cast<uint32_t>(13), static_cast<uint32_t>(14),
+              static_cast<uint32_t>(15));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetTransformFeedbackVarying::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.index);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.name_bucket_id);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.result_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(15), cmd.result_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, GetUniformBlockIndex) {
   cmds::GetUniformBlockIndex& cmd = *GetBufferAs<cmds::GetUniformBlockIndex>();
   void* next_cmd =
@@ -1478,6 +1531,21 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, GetUniformIndices) {
+  cmds::GetUniformIndices& cmd = *GetBufferAs<cmds::GetUniformIndices>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12),
+              static_cast<uint32_t>(13), static_cast<uint32_t>(14));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetUniformIndices::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.names_bucket_id);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.indices_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.indices_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, GetUniformLocation) {
   cmds::GetUniformLocation& cmd = *GetBufferAs<cmds::GetUniformLocation>();
   void* next_cmd =
@@ -2716,6 +2784,19 @@
   // TODO(gman): Check that data was inserted;
 }
 
+TEST_F(GLES2FormatTest, UniformBlockBinding) {
+  cmds::UniformBlockBinding& cmd = *GetBufferAs<cmds::UniformBlockBinding>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11),
+                           static_cast<GLuint>(12), static_cast<GLuint>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::UniformBlockBinding::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.index);
+  EXPECT_EQ(static_cast<GLuint>(13), cmd.binding);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, UniformMatrix2fvImmediate) {
   const int kSomeBaseValueToTestWith = 51;
   static GLfloat data[] = {
@@ -3713,6 +3794,33 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, GetTransformFeedbackVaryingsCHROMIUM) {
+  cmds::GetTransformFeedbackVaryingsCHROMIUM& cmd =
+      *GetBufferAs<cmds::GetTransformFeedbackVaryingsCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::GetTransformFeedbackVaryingsCHROMIUM::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.bucket_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetUniformsES3CHROMIUM) {
+  cmds::GetUniformsES3CHROMIUM& cmd =
+      *GetBufferAs<cmds::GetUniformsES3CHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetUniformsES3CHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.bucket_id);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, GetTranslatedShaderSourceANGLE) {
   cmds::GetTranslatedShaderSourceANGLE& cmd =
       *GetBufferAs<cmds::GetTranslatedShaderSourceANGLE>();
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 76364b7..db67f4f 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -87,198 +87,205 @@
   OP(GenTransformFeedbacksImmediate)           /* 328 */ \
   OP(GetActiveAttrib)                          /* 329 */ \
   OP(GetActiveUniform)                         /* 330 */ \
-  OP(GetActiveUniformBlockName)                /* 331 */ \
-  OP(GetAttachedShaders)                       /* 332 */ \
-  OP(GetAttribLocation)                        /* 333 */ \
-  OP(GetBooleanv)                              /* 334 */ \
-  OP(GetBufferParameteriv)                     /* 335 */ \
-  OP(GetError)                                 /* 336 */ \
-  OP(GetFloatv)                                /* 337 */ \
-  OP(GetFragDataLocation)                      /* 338 */ \
-  OP(GetFramebufferAttachmentParameteriv)      /* 339 */ \
-  OP(GetIntegerv)                              /* 340 */ \
-  OP(GetInternalformativ)                      /* 341 */ \
-  OP(GetProgramiv)                             /* 342 */ \
-  OP(GetProgramInfoLog)                        /* 343 */ \
-  OP(GetRenderbufferParameteriv)               /* 344 */ \
-  OP(GetSamplerParameterfv)                    /* 345 */ \
-  OP(GetSamplerParameteriv)                    /* 346 */ \
-  OP(GetShaderiv)                              /* 347 */ \
-  OP(GetShaderInfoLog)                         /* 348 */ \
-  OP(GetShaderPrecisionFormat)                 /* 349 */ \
-  OP(GetShaderSource)                          /* 350 */ \
-  OP(GetString)                                /* 351 */ \
-  OP(GetTexParameterfv)                        /* 352 */ \
-  OP(GetTexParameteriv)                        /* 353 */ \
-  OP(GetUniformBlockIndex)                     /* 354 */ \
-  OP(GetUniformfv)                             /* 355 */ \
-  OP(GetUniformiv)                             /* 356 */ \
-  OP(GetUniformLocation)                       /* 357 */ \
-  OP(GetVertexAttribfv)                        /* 358 */ \
-  OP(GetVertexAttribiv)                        /* 359 */ \
-  OP(GetVertexAttribPointerv)                  /* 360 */ \
-  OP(Hint)                                     /* 361 */ \
-  OP(InvalidateFramebufferImmediate)           /* 362 */ \
-  OP(InvalidateSubFramebufferImmediate)        /* 363 */ \
-  OP(IsBuffer)                                 /* 364 */ \
-  OP(IsEnabled)                                /* 365 */ \
-  OP(IsFramebuffer)                            /* 366 */ \
-  OP(IsProgram)                                /* 367 */ \
-  OP(IsRenderbuffer)                           /* 368 */ \
-  OP(IsSampler)                                /* 369 */ \
-  OP(IsShader)                                 /* 370 */ \
-  OP(IsSync)                                   /* 371 */ \
-  OP(IsTexture)                                /* 372 */ \
-  OP(IsTransformFeedback)                      /* 373 */ \
-  OP(LineWidth)                                /* 374 */ \
-  OP(LinkProgram)                              /* 375 */ \
-  OP(PauseTransformFeedback)                   /* 376 */ \
-  OP(PixelStorei)                              /* 377 */ \
-  OP(PolygonOffset)                            /* 378 */ \
-  OP(ReadBuffer)                               /* 379 */ \
-  OP(ReadPixels)                               /* 380 */ \
-  OP(ReleaseShaderCompiler)                    /* 381 */ \
-  OP(RenderbufferStorage)                      /* 382 */ \
-  OP(ResumeTransformFeedback)                  /* 383 */ \
-  OP(SampleCoverage)                           /* 384 */ \
-  OP(SamplerParameterf)                        /* 385 */ \
-  OP(SamplerParameterfvImmediate)              /* 386 */ \
-  OP(SamplerParameteri)                        /* 387 */ \
-  OP(SamplerParameterivImmediate)              /* 388 */ \
-  OP(Scissor)                                  /* 389 */ \
-  OP(ShaderBinary)                             /* 390 */ \
-  OP(ShaderSourceBucket)                       /* 391 */ \
-  OP(StencilFunc)                              /* 392 */ \
-  OP(StencilFuncSeparate)                      /* 393 */ \
-  OP(StencilMask)                              /* 394 */ \
-  OP(StencilMaskSeparate)                      /* 395 */ \
-  OP(StencilOp)                                /* 396 */ \
-  OP(StencilOpSeparate)                        /* 397 */ \
-  OP(TexImage2D)                               /* 398 */ \
-  OP(TexImage3D)                               /* 399 */ \
-  OP(TexParameterf)                            /* 400 */ \
-  OP(TexParameterfvImmediate)                  /* 401 */ \
-  OP(TexParameteri)                            /* 402 */ \
-  OP(TexParameterivImmediate)                  /* 403 */ \
-  OP(TexStorage3D)                             /* 404 */ \
-  OP(TexSubImage2D)                            /* 405 */ \
-  OP(TexSubImage3D)                            /* 406 */ \
-  OP(TransformFeedbackVaryingsBucket)          /* 407 */ \
-  OP(Uniform1f)                                /* 408 */ \
-  OP(Uniform1fvImmediate)                      /* 409 */ \
-  OP(Uniform1i)                                /* 410 */ \
-  OP(Uniform1ivImmediate)                      /* 411 */ \
-  OP(Uniform1ui)                               /* 412 */ \
-  OP(Uniform1uivImmediate)                     /* 413 */ \
-  OP(Uniform2f)                                /* 414 */ \
-  OP(Uniform2fvImmediate)                      /* 415 */ \
-  OP(Uniform2i)                                /* 416 */ \
-  OP(Uniform2ivImmediate)                      /* 417 */ \
-  OP(Uniform2ui)                               /* 418 */ \
-  OP(Uniform2uivImmediate)                     /* 419 */ \
-  OP(Uniform3f)                                /* 420 */ \
-  OP(Uniform3fvImmediate)                      /* 421 */ \
-  OP(Uniform3i)                                /* 422 */ \
-  OP(Uniform3ivImmediate)                      /* 423 */ \
-  OP(Uniform3ui)                               /* 424 */ \
-  OP(Uniform3uivImmediate)                     /* 425 */ \
-  OP(Uniform4f)                                /* 426 */ \
-  OP(Uniform4fvImmediate)                      /* 427 */ \
-  OP(Uniform4i)                                /* 428 */ \
-  OP(Uniform4ivImmediate)                      /* 429 */ \
-  OP(Uniform4ui)                               /* 430 */ \
-  OP(Uniform4uivImmediate)                     /* 431 */ \
-  OP(UniformMatrix2fvImmediate)                /* 432 */ \
-  OP(UniformMatrix2x3fvImmediate)              /* 433 */ \
-  OP(UniformMatrix2x4fvImmediate)              /* 434 */ \
-  OP(UniformMatrix3fvImmediate)                /* 435 */ \
-  OP(UniformMatrix3x2fvImmediate)              /* 436 */ \
-  OP(UniformMatrix3x4fvImmediate)              /* 437 */ \
-  OP(UniformMatrix4fvImmediate)                /* 438 */ \
-  OP(UniformMatrix4x2fvImmediate)              /* 439 */ \
-  OP(UniformMatrix4x3fvImmediate)              /* 440 */ \
-  OP(UseProgram)                               /* 441 */ \
-  OP(ValidateProgram)                          /* 442 */ \
-  OP(VertexAttrib1f)                           /* 443 */ \
-  OP(VertexAttrib1fvImmediate)                 /* 444 */ \
-  OP(VertexAttrib2f)                           /* 445 */ \
-  OP(VertexAttrib2fvImmediate)                 /* 446 */ \
-  OP(VertexAttrib3f)                           /* 447 */ \
-  OP(VertexAttrib3fvImmediate)                 /* 448 */ \
-  OP(VertexAttrib4f)                           /* 449 */ \
-  OP(VertexAttrib4fvImmediate)                 /* 450 */ \
-  OP(VertexAttribI4i)                          /* 451 */ \
-  OP(VertexAttribI4ivImmediate)                /* 452 */ \
-  OP(VertexAttribI4ui)                         /* 453 */ \
-  OP(VertexAttribI4uivImmediate)               /* 454 */ \
-  OP(VertexAttribIPointer)                     /* 455 */ \
-  OP(VertexAttribPointer)                      /* 456 */ \
-  OP(Viewport)                                 /* 457 */ \
-  OP(BlitFramebufferCHROMIUM)                  /* 458 */ \
-  OP(RenderbufferStorageMultisampleCHROMIUM)   /* 459 */ \
-  OP(RenderbufferStorageMultisampleEXT)        /* 460 */ \
-  OP(FramebufferTexture2DMultisampleEXT)       /* 461 */ \
-  OP(TexStorage2DEXT)                          /* 462 */ \
-  OP(GenQueriesEXTImmediate)                   /* 463 */ \
-  OP(DeleteQueriesEXTImmediate)                /* 464 */ \
-  OP(BeginQueryEXT)                            /* 465 */ \
-  OP(BeginTransformFeedback)                   /* 466 */ \
-  OP(EndQueryEXT)                              /* 467 */ \
-  OP(EndTransformFeedback)                     /* 468 */ \
-  OP(InsertEventMarkerEXT)                     /* 469 */ \
-  OP(PushGroupMarkerEXT)                       /* 470 */ \
-  OP(PopGroupMarkerEXT)                        /* 471 */ \
-  OP(GenVertexArraysOESImmediate)              /* 472 */ \
-  OP(DeleteVertexArraysOESImmediate)           /* 473 */ \
-  OP(IsVertexArrayOES)                         /* 474 */ \
-  OP(BindVertexArrayOES)                       /* 475 */ \
-  OP(SwapBuffers)                              /* 476 */ \
-  OP(GetMaxValueInBufferCHROMIUM)              /* 477 */ \
-  OP(EnableFeatureCHROMIUM)                    /* 478 */ \
-  OP(ResizeCHROMIUM)                           /* 479 */ \
-  OP(GetRequestableExtensionsCHROMIUM)         /* 480 */ \
-  OP(RequestExtensionCHROMIUM)                 /* 481 */ \
-  OP(GetProgramInfoCHROMIUM)                   /* 482 */ \
-  OP(GetUniformBlocksCHROMIUM)                 /* 483 */ \
-  OP(GetTranslatedShaderSourceANGLE)           /* 484 */ \
-  OP(PostSubBufferCHROMIUM)                    /* 485 */ \
-  OP(TexImageIOSurface2DCHROMIUM)              /* 486 */ \
-  OP(CopyTextureCHROMIUM)                      /* 487 */ \
-  OP(DrawArraysInstancedANGLE)                 /* 488 */ \
-  OP(DrawElementsInstancedANGLE)               /* 489 */ \
-  OP(VertexAttribDivisorANGLE)                 /* 490 */ \
-  OP(GenMailboxCHROMIUM)                       /* 491 */ \
-  OP(ProduceTextureCHROMIUMImmediate)          /* 492 */ \
-  OP(ProduceTextureDirectCHROMIUMImmediate)    /* 493 */ \
-  OP(ConsumeTextureCHROMIUMImmediate)          /* 494 */ \
-  OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 495 */ \
-  OP(BindUniformLocationCHROMIUMBucket)        /* 496 */ \
-  OP(GenValuebuffersCHROMIUMImmediate)         /* 497 */ \
-  OP(DeleteValuebuffersCHROMIUMImmediate)      /* 498 */ \
-  OP(IsValuebufferCHROMIUM)                    /* 499 */ \
-  OP(BindValuebufferCHROMIUM)                  /* 500 */ \
-  OP(SubscribeValueCHROMIUM)                   /* 501 */ \
-  OP(PopulateSubscribedValuesCHROMIUM)         /* 502 */ \
-  OP(UniformValuebufferCHROMIUM)               /* 503 */ \
-  OP(BindTexImage2DCHROMIUM)                   /* 504 */ \
-  OP(ReleaseTexImage2DCHROMIUM)                /* 505 */ \
-  OP(TraceBeginCHROMIUM)                       /* 506 */ \
-  OP(TraceEndCHROMIUM)                         /* 507 */ \
-  OP(AsyncTexSubImage2DCHROMIUM)               /* 508 */ \
-  OP(AsyncTexImage2DCHROMIUM)                  /* 509 */ \
-  OP(WaitAsyncTexImage2DCHROMIUM)              /* 510 */ \
-  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 511 */ \
-  OP(DiscardFramebufferEXTImmediate)           /* 512 */ \
-  OP(LoseContextCHROMIUM)                      /* 513 */ \
-  OP(InsertSyncPointCHROMIUM)                  /* 514 */ \
-  OP(WaitSyncPointCHROMIUM)                    /* 515 */ \
-  OP(DrawBuffersEXTImmediate)                  /* 516 */ \
-  OP(DiscardBackbufferCHROMIUM)                /* 517 */ \
-  OP(ScheduleOverlayPlaneCHROMIUM)             /* 518 */ \
-  OP(SwapInterval)                             /* 519 */ \
-  OP(MatrixLoadfCHROMIUMImmediate)             /* 520 */ \
-  OP(MatrixLoadIdentityCHROMIUM)               /* 521 */ \
-  OP(BlendBarrierKHR)                          /* 522 */
+  OP(GetActiveUniformBlockiv)                  /* 331 */ \
+  OP(GetActiveUniformBlockName)                /* 332 */ \
+  OP(GetActiveUniformsiv)                      /* 333 */ \
+  OP(GetAttachedShaders)                       /* 334 */ \
+  OP(GetAttribLocation)                        /* 335 */ \
+  OP(GetBooleanv)                              /* 336 */ \
+  OP(GetBufferParameteriv)                     /* 337 */ \
+  OP(GetError)                                 /* 338 */ \
+  OP(GetFloatv)                                /* 339 */ \
+  OP(GetFragDataLocation)                      /* 340 */ \
+  OP(GetFramebufferAttachmentParameteriv)      /* 341 */ \
+  OP(GetIntegerv)                              /* 342 */ \
+  OP(GetInternalformativ)                      /* 343 */ \
+  OP(GetProgramiv)                             /* 344 */ \
+  OP(GetProgramInfoLog)                        /* 345 */ \
+  OP(GetRenderbufferParameteriv)               /* 346 */ \
+  OP(GetSamplerParameterfv)                    /* 347 */ \
+  OP(GetSamplerParameteriv)                    /* 348 */ \
+  OP(GetShaderiv)                              /* 349 */ \
+  OP(GetShaderInfoLog)                         /* 350 */ \
+  OP(GetShaderPrecisionFormat)                 /* 351 */ \
+  OP(GetShaderSource)                          /* 352 */ \
+  OP(GetString)                                /* 353 */ \
+  OP(GetTexParameterfv)                        /* 354 */ \
+  OP(GetTexParameteriv)                        /* 355 */ \
+  OP(GetTransformFeedbackVarying)              /* 356 */ \
+  OP(GetUniformBlockIndex)                     /* 357 */ \
+  OP(GetUniformfv)                             /* 358 */ \
+  OP(GetUniformiv)                             /* 359 */ \
+  OP(GetUniformIndices)                        /* 360 */ \
+  OP(GetUniformLocation)                       /* 361 */ \
+  OP(GetVertexAttribfv)                        /* 362 */ \
+  OP(GetVertexAttribiv)                        /* 363 */ \
+  OP(GetVertexAttribPointerv)                  /* 364 */ \
+  OP(Hint)                                     /* 365 */ \
+  OP(InvalidateFramebufferImmediate)           /* 366 */ \
+  OP(InvalidateSubFramebufferImmediate)        /* 367 */ \
+  OP(IsBuffer)                                 /* 368 */ \
+  OP(IsEnabled)                                /* 369 */ \
+  OP(IsFramebuffer)                            /* 370 */ \
+  OP(IsProgram)                                /* 371 */ \
+  OP(IsRenderbuffer)                           /* 372 */ \
+  OP(IsSampler)                                /* 373 */ \
+  OP(IsShader)                                 /* 374 */ \
+  OP(IsSync)                                   /* 375 */ \
+  OP(IsTexture)                                /* 376 */ \
+  OP(IsTransformFeedback)                      /* 377 */ \
+  OP(LineWidth)                                /* 378 */ \
+  OP(LinkProgram)                              /* 379 */ \
+  OP(PauseTransformFeedback)                   /* 380 */ \
+  OP(PixelStorei)                              /* 381 */ \
+  OP(PolygonOffset)                            /* 382 */ \
+  OP(ReadBuffer)                               /* 383 */ \
+  OP(ReadPixels)                               /* 384 */ \
+  OP(ReleaseShaderCompiler)                    /* 385 */ \
+  OP(RenderbufferStorage)                      /* 386 */ \
+  OP(ResumeTransformFeedback)                  /* 387 */ \
+  OP(SampleCoverage)                           /* 388 */ \
+  OP(SamplerParameterf)                        /* 389 */ \
+  OP(SamplerParameterfvImmediate)              /* 390 */ \
+  OP(SamplerParameteri)                        /* 391 */ \
+  OP(SamplerParameterivImmediate)              /* 392 */ \
+  OP(Scissor)                                  /* 393 */ \
+  OP(ShaderBinary)                             /* 394 */ \
+  OP(ShaderSourceBucket)                       /* 395 */ \
+  OP(StencilFunc)                              /* 396 */ \
+  OP(StencilFuncSeparate)                      /* 397 */ \
+  OP(StencilMask)                              /* 398 */ \
+  OP(StencilMaskSeparate)                      /* 399 */ \
+  OP(StencilOp)                                /* 400 */ \
+  OP(StencilOpSeparate)                        /* 401 */ \
+  OP(TexImage2D)                               /* 402 */ \
+  OP(TexImage3D)                               /* 403 */ \
+  OP(TexParameterf)                            /* 404 */ \
+  OP(TexParameterfvImmediate)                  /* 405 */ \
+  OP(TexParameteri)                            /* 406 */ \
+  OP(TexParameterivImmediate)                  /* 407 */ \
+  OP(TexStorage3D)                             /* 408 */ \
+  OP(TexSubImage2D)                            /* 409 */ \
+  OP(TexSubImage3D)                            /* 410 */ \
+  OP(TransformFeedbackVaryingsBucket)          /* 411 */ \
+  OP(Uniform1f)                                /* 412 */ \
+  OP(Uniform1fvImmediate)                      /* 413 */ \
+  OP(Uniform1i)                                /* 414 */ \
+  OP(Uniform1ivImmediate)                      /* 415 */ \
+  OP(Uniform1ui)                               /* 416 */ \
+  OP(Uniform1uivImmediate)                     /* 417 */ \
+  OP(Uniform2f)                                /* 418 */ \
+  OP(Uniform2fvImmediate)                      /* 419 */ \
+  OP(Uniform2i)                                /* 420 */ \
+  OP(Uniform2ivImmediate)                      /* 421 */ \
+  OP(Uniform2ui)                               /* 422 */ \
+  OP(Uniform2uivImmediate)                     /* 423 */ \
+  OP(Uniform3f)                                /* 424 */ \
+  OP(Uniform3fvImmediate)                      /* 425 */ \
+  OP(Uniform3i)                                /* 426 */ \
+  OP(Uniform3ivImmediate)                      /* 427 */ \
+  OP(Uniform3ui)                               /* 428 */ \
+  OP(Uniform3uivImmediate)                     /* 429 */ \
+  OP(Uniform4f)                                /* 430 */ \
+  OP(Uniform4fvImmediate)                      /* 431 */ \
+  OP(Uniform4i)                                /* 432 */ \
+  OP(Uniform4ivImmediate)                      /* 433 */ \
+  OP(Uniform4ui)                               /* 434 */ \
+  OP(Uniform4uivImmediate)                     /* 435 */ \
+  OP(UniformBlockBinding)                      /* 436 */ \
+  OP(UniformMatrix2fvImmediate)                /* 437 */ \
+  OP(UniformMatrix2x3fvImmediate)              /* 438 */ \
+  OP(UniformMatrix2x4fvImmediate)              /* 439 */ \
+  OP(UniformMatrix3fvImmediate)                /* 440 */ \
+  OP(UniformMatrix3x2fvImmediate)              /* 441 */ \
+  OP(UniformMatrix3x4fvImmediate)              /* 442 */ \
+  OP(UniformMatrix4fvImmediate)                /* 443 */ \
+  OP(UniformMatrix4x2fvImmediate)              /* 444 */ \
+  OP(UniformMatrix4x3fvImmediate)              /* 445 */ \
+  OP(UseProgram)                               /* 446 */ \
+  OP(ValidateProgram)                          /* 447 */ \
+  OP(VertexAttrib1f)                           /* 448 */ \
+  OP(VertexAttrib1fvImmediate)                 /* 449 */ \
+  OP(VertexAttrib2f)                           /* 450 */ \
+  OP(VertexAttrib2fvImmediate)                 /* 451 */ \
+  OP(VertexAttrib3f)                           /* 452 */ \
+  OP(VertexAttrib3fvImmediate)                 /* 453 */ \
+  OP(VertexAttrib4f)                           /* 454 */ \
+  OP(VertexAttrib4fvImmediate)                 /* 455 */ \
+  OP(VertexAttribI4i)                          /* 456 */ \
+  OP(VertexAttribI4ivImmediate)                /* 457 */ \
+  OP(VertexAttribI4ui)                         /* 458 */ \
+  OP(VertexAttribI4uivImmediate)               /* 459 */ \
+  OP(VertexAttribIPointer)                     /* 460 */ \
+  OP(VertexAttribPointer)                      /* 461 */ \
+  OP(Viewport)                                 /* 462 */ \
+  OP(BlitFramebufferCHROMIUM)                  /* 463 */ \
+  OP(RenderbufferStorageMultisampleCHROMIUM)   /* 464 */ \
+  OP(RenderbufferStorageMultisampleEXT)        /* 465 */ \
+  OP(FramebufferTexture2DMultisampleEXT)       /* 466 */ \
+  OP(TexStorage2DEXT)                          /* 467 */ \
+  OP(GenQueriesEXTImmediate)                   /* 468 */ \
+  OP(DeleteQueriesEXTImmediate)                /* 469 */ \
+  OP(BeginQueryEXT)                            /* 470 */ \
+  OP(BeginTransformFeedback)                   /* 471 */ \
+  OP(EndQueryEXT)                              /* 472 */ \
+  OP(EndTransformFeedback)                     /* 473 */ \
+  OP(InsertEventMarkerEXT)                     /* 474 */ \
+  OP(PushGroupMarkerEXT)                       /* 475 */ \
+  OP(PopGroupMarkerEXT)                        /* 476 */ \
+  OP(GenVertexArraysOESImmediate)              /* 477 */ \
+  OP(DeleteVertexArraysOESImmediate)           /* 478 */ \
+  OP(IsVertexArrayOES)                         /* 479 */ \
+  OP(BindVertexArrayOES)                       /* 480 */ \
+  OP(SwapBuffers)                              /* 481 */ \
+  OP(GetMaxValueInBufferCHROMIUM)              /* 482 */ \
+  OP(EnableFeatureCHROMIUM)                    /* 483 */ \
+  OP(ResizeCHROMIUM)                           /* 484 */ \
+  OP(GetRequestableExtensionsCHROMIUM)         /* 485 */ \
+  OP(RequestExtensionCHROMIUM)                 /* 486 */ \
+  OP(GetProgramInfoCHROMIUM)                   /* 487 */ \
+  OP(GetUniformBlocksCHROMIUM)                 /* 488 */ \
+  OP(GetTransformFeedbackVaryingsCHROMIUM)     /* 489 */ \
+  OP(GetUniformsES3CHROMIUM)                   /* 490 */ \
+  OP(GetTranslatedShaderSourceANGLE)           /* 491 */ \
+  OP(PostSubBufferCHROMIUM)                    /* 492 */ \
+  OP(TexImageIOSurface2DCHROMIUM)              /* 493 */ \
+  OP(CopyTextureCHROMIUM)                      /* 494 */ \
+  OP(DrawArraysInstancedANGLE)                 /* 495 */ \
+  OP(DrawElementsInstancedANGLE)               /* 496 */ \
+  OP(VertexAttribDivisorANGLE)                 /* 497 */ \
+  OP(GenMailboxCHROMIUM)                       /* 498 */ \
+  OP(ProduceTextureCHROMIUMImmediate)          /* 499 */ \
+  OP(ProduceTextureDirectCHROMIUMImmediate)    /* 500 */ \
+  OP(ConsumeTextureCHROMIUMImmediate)          /* 501 */ \
+  OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 502 */ \
+  OP(BindUniformLocationCHROMIUMBucket)        /* 503 */ \
+  OP(GenValuebuffersCHROMIUMImmediate)         /* 504 */ \
+  OP(DeleteValuebuffersCHROMIUMImmediate)      /* 505 */ \
+  OP(IsValuebufferCHROMIUM)                    /* 506 */ \
+  OP(BindValuebufferCHROMIUM)                  /* 507 */ \
+  OP(SubscribeValueCHROMIUM)                   /* 508 */ \
+  OP(PopulateSubscribedValuesCHROMIUM)         /* 509 */ \
+  OP(UniformValuebufferCHROMIUM)               /* 510 */ \
+  OP(BindTexImage2DCHROMIUM)                   /* 511 */ \
+  OP(ReleaseTexImage2DCHROMIUM)                /* 512 */ \
+  OP(TraceBeginCHROMIUM)                       /* 513 */ \
+  OP(TraceEndCHROMIUM)                         /* 514 */ \
+  OP(AsyncTexSubImage2DCHROMIUM)               /* 515 */ \
+  OP(AsyncTexImage2DCHROMIUM)                  /* 516 */ \
+  OP(WaitAsyncTexImage2DCHROMIUM)              /* 517 */ \
+  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 518 */ \
+  OP(DiscardFramebufferEXTImmediate)           /* 519 */ \
+  OP(LoseContextCHROMIUM)                      /* 520 */ \
+  OP(InsertSyncPointCHROMIUM)                  /* 521 */ \
+  OP(WaitSyncPointCHROMIUM)                    /* 522 */ \
+  OP(DrawBuffersEXTImmediate)                  /* 523 */ \
+  OP(DiscardBackbufferCHROMIUM)                /* 524 */ \
+  OP(ScheduleOverlayPlaneCHROMIUM)             /* 525 */ \
+  OP(SwapInterval)                             /* 526 */ \
+  OP(MatrixLoadfCHROMIUMImmediate)             /* 527 */ \
+  OP(MatrixLoadIdentityCHROMIUM)               /* 528 */ \
+  OP(BlendBarrierKHR)                          /* 529 */
 
 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 a2f4ca7..17a53db 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -78,6 +78,8 @@
 static std::string GetStringTextureWrapMode(uint32_t value);
 static std::string GetStringTransformFeedbackBindTarget(uint32_t value);
 static std::string GetStringTransformFeedbackPrimitiveMode(uint32_t value);
+static std::string GetStringUniformBlockParameter(uint32_t value);
+static std::string GetStringUniformParameter(uint32_t value);
 static std::string GetStringValueBufferTarget(uint32_t value);
 static std::string GetStringVertexAttribType(uint32_t value);
 static std::string GetStringVertexAttribute(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 db3a6c4..273b1e0 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -5260,6 +5260,38 @@
                                            arraysize(string_table), value);
 }
 
+std::string GLES2Util::GetStringUniformBlockParameter(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_UNIFORM_BLOCK_BINDING, "GL_UNIFORM_BLOCK_BINDING"},
+      {GL_UNIFORM_BLOCK_DATA_SIZE, "GL_UNIFORM_BLOCK_DATA_SIZE"},
+      {GL_UNIFORM_BLOCK_NAME_LENGTH, "GL_UNIFORM_BLOCK_NAME_LENGTH"},
+      {GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, "GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS"},
+      {GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
+       "GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES"},
+      {GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
+       "GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER"},
+      {GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER,
+       "GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringUniformParameter(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_UNIFORM_SIZE, "GL_UNIFORM_SIZE"},
+      {GL_UNIFORM_TYPE, "GL_UNIFORM_TYPE"},
+      {GL_UNIFORM_NAME_LENGTH, "GL_UNIFORM_NAME_LENGTH"},
+      {GL_UNIFORM_BLOCK_INDEX, "GL_UNIFORM_BLOCK_INDEX"},
+      {GL_UNIFORM_OFFSET, "GL_UNIFORM_OFFSET"},
+      {GL_UNIFORM_ARRAY_STRIDE, "GL_UNIFORM_ARRAY_STRIDE"},
+      {GL_UNIFORM_MATRIX_STRIDE, "GL_UNIFORM_MATRIX_STRIDE"},
+      {GL_UNIFORM_IS_ROW_MAJOR, "GL_UNIFORM_IS_ROW_MAJOR"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
 std::string GLES2Util::GetStringValueBufferTarget(uint32_t value) {
   static const EnumToString string_table[] = {
       {GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 58c9977..219a4c6 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -9,6 +9,8 @@
   sources = [
     "async_pixel_transfer_delegate.cc",
     "async_pixel_transfer_delegate.h",
+    "async_pixel_transfer_manager.cc",
+    "async_pixel_transfer_manager.h",
     "async_pixel_transfer_manager_android.cc",
     "async_pixel_transfer_manager_idle.cc",
     "async_pixel_transfer_manager_idle.h",
@@ -21,10 +23,8 @@
     "async_pixel_transfer_manager_sync.cc",
     "async_pixel_transfer_manager_sync.h",
     "async_pixel_transfer_manager_win.cc",
-    "async_pixel_transfer_manager.cc",
-    "async_pixel_transfer_manager.h",
-    "buffer_manager.h",
     "buffer_manager.cc",
+    "buffer_manager.h",
     "cmd_buffer_engine.h",
     "cmd_parser.cc",
     "cmd_parser.h",
@@ -32,34 +32,34 @@
     "command_buffer_service.h",
     "common_decoder.cc",
     "common_decoder.h",
-    "context_group.h",
     "context_group.cc",
+    "context_group.h",
+    "context_state.cc",
     "context_state.h",
     "context_state_autogen.h",
     "context_state_impl_autogen.h",
-    "context_state.cc",
     "error_state.cc",
     "error_state.h",
-    "feature_info.h",
     "feature_info.cc",
-    "framebuffer_manager.h",
+    "feature_info.h",
     "framebuffer_manager.cc",
-    "gles2_cmd_clear_framebuffer.cc",
-    "gles2_cmd_clear_framebuffer.h",
-    "gles2_cmd_copy_texture_chromium.cc",
-    "gles2_cmd_copy_texture_chromium.h",
-    "gles2_cmd_decoder.h",
-    "gles2_cmd_decoder_autogen.h",
-    "gles2_cmd_decoder.cc",
-    "gles2_cmd_validation.h",
-    "gles2_cmd_validation.cc",
-    "gles2_cmd_validation_autogen.h",
-    "gles2_cmd_validation_implementation_autogen.h",
+    "framebuffer_manager.h",
     "gl_context_virtual.cc",
     "gl_context_virtual.h",
     "gl_state_restorer_impl.cc",
     "gl_state_restorer_impl.h",
     "gl_utils.h",
+    "gles2_cmd_clear_framebuffer.cc",
+    "gles2_cmd_clear_framebuffer.h",
+    "gles2_cmd_copy_texture_chromium.cc",
+    "gles2_cmd_copy_texture_chromium.h",
+    "gles2_cmd_decoder.cc",
+    "gles2_cmd_decoder.h",
+    "gles2_cmd_decoder_autogen.h",
+    "gles2_cmd_validation.cc",
+    "gles2_cmd_validation.h",
+    "gles2_cmd_validation_autogen.h",
+    "gles2_cmd_validation_implementation_autogen.h",
     "gpu_scheduler.cc",
     "gpu_scheduler.h",
     "gpu_scheduler_mock.h",
@@ -67,10 +67,12 @@
     "gpu_state_tracer.h",
     "gpu_switches.cc",
     "gpu_switches.h",
+    "gpu_timing.cc",
+    "gpu_timing.h",
     "gpu_tracer.cc",
     "gpu_tracer.h",
-    "id_manager.h",
     "id_manager.cc",
+    "id_manager.h",
     "image_factory.cc",
     "image_factory.h",
     "image_manager.cc",
@@ -84,39 +86,39 @@
     "mailbox_manager_impl.h",
     "mailbox_manager_sync.cc",
     "mailbox_manager_sync.h",
-    "memory_program_cache.h",
     "memory_program_cache.cc",
+    "memory_program_cache.h",
     "mocks.h",
-    "program_manager.h",
-    "program_manager.cc",
-    "query_manager.h",
-    "query_manager.cc",
-    "renderbuffer_manager.h",
-    "renderbuffer_manager.cc",
-    "program_cache.h",
     "program_cache.cc",
-    "shader_manager.h",
+    "program_cache.h",
+    "program_manager.cc",
+    "program_manager.h",
+    "query_manager.cc",
+    "query_manager.h",
+    "renderbuffer_manager.cc",
+    "renderbuffer_manager.h",
     "shader_manager.cc",
-    "shader_translator.h",
+    "shader_manager.h",
     "shader_translator.cc",
-    "shader_translator_cache.h",
+    "shader_translator.h",
     "shader_translator_cache.cc",
-    "stream_texture_manager_in_process_android.h",
+    "shader_translator_cache.h",
     "stream_texture_manager_in_process_android.cc",
-    "sync_point_manager.h",
+    "stream_texture_manager_in_process_android.h",
     "sync_point_manager.cc",
-    "texture_definition.h",
+    "sync_point_manager.h",
     "texture_definition.cc",
-    "texture_manager.h",
+    "texture_definition.h",
     "texture_manager.cc",
+    "texture_manager.h",
     "transfer_buffer_manager.cc",
     "transfer_buffer_manager.h",
-    "valuebuffer_manager.h",
     "valuebuffer_manager.cc",
-    "vertex_array_manager.h",
+    "valuebuffer_manager.h",
     "vertex_array_manager.cc",
-    "vertex_attrib_manager.h",
+    "vertex_array_manager.h",
     "vertex_attrib_manager.cc",
+    "vertex_attrib_manager.h",
   ]
 
   defines = [ "GPU_IMPLEMENTATION" ]
diff --git a/gpu/command_buffer/service/common_decoder.cc b/gpu/command_buffer/service/common_decoder.cc
index f40c721..99fdb76 100644
--- a/gpu/command_buffer/service/common_decoder.cc
+++ b/gpu/command_buffer/service/common_decoder.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "gpu/command_buffer/service/common_decoder.h"
+
+#include "base/numerics/safe_math.h"
 #include "gpu/command_buffer/service/cmd_buffer_engine.h"
 
 namespace gpu {
@@ -69,6 +71,53 @@
   return true;
 }
 
+bool CommonDecoder::Bucket::GetAsStrings(
+    GLsizei* _count, std::vector<char*>* _string, std::vector<GLint>* _length) {
+  const size_t kMinBucketSize = sizeof(GLint);
+  // Each string has at least |length| in the header and a NUL character.
+  const size_t kMinStringSize = sizeof(GLint) + 1;
+  const size_t bucket_size = this->size();
+  if (bucket_size < kMinBucketSize) {
+    return false;
+  }
+  char* bucket_data = this->GetDataAs<char*>(0, bucket_size);
+  GLint* header = reinterpret_cast<GLint*>(bucket_data);
+  GLsizei count = static_cast<GLsizei>(header[0]);
+  if (count < 0) {
+    return false;
+  }
+  const size_t max_count = (bucket_size - kMinBucketSize) / kMinStringSize;
+  if (max_count < static_cast<size_t>(count)) {
+    return false;
+  }
+  GLint* length = header + 1;
+  std::vector<char*> strs(count);
+  base::CheckedNumeric<size_t> total_size = sizeof(GLint);
+  total_size *= count + 1;  // Header size.
+  if (!total_size.IsValid())
+    return false;
+  for (GLsizei ii = 0; ii < count; ++ii) {
+    strs[ii] = bucket_data + total_size.ValueOrDefault(0);
+    total_size += length[ii];
+    total_size += 1;  // NUL char at the end of each char array.
+    if (!total_size.IsValid() || total_size.ValueOrDefault(0) > bucket_size ||
+        strs[ii][length[ii]] != 0) {
+      return false;
+    }
+  }
+  if (total_size.ValueOrDefault(0) != bucket_size) {
+    return false;
+  }
+  DCHECK(_count && _string && _length);
+  *_count = count;
+  *_string = strs;
+  _length->resize(count);
+  for (GLsizei ii = 0; ii < count; ++ii) {
+    (*_length)[ii] = length[ii];
+  }
+  return true;
+}
+
 CommonDecoder::CommonDecoder() : engine_(NULL) {}
 
 CommonDecoder::~CommonDecoder() {}
diff --git a/gpu/command_buffer/service/common_decoder.h b/gpu/command_buffer/service/common_decoder.h
index fc9ecf2..53de875 100644
--- a/gpu/command_buffer/service/common_decoder.h
+++ b/gpu/command_buffer/service/common_decoder.h
@@ -14,6 +14,10 @@
 #include "gpu/command_buffer/service/cmd_parser.h"
 #include "gpu/gpu_export.h"
 
+// Forwardly declare a few GL types to avoid including GL header files.
+typedef int GLsizei;
+typedef int GLint;
+
 namespace gpu {
 
 class CommandBufferEngine;
@@ -82,6 +86,13 @@
     // is no string.
     bool GetAsString(std::string* str);
 
+    // Gets the bucket data as strings.
+    // On success, the number of strings are in |_count|, the string data are
+    // in |_string|, and string sizes are in |_length|..
+    bool GetAsStrings(GLsizei* _count,
+                      std::vector<char*>* _string,
+                      std::vector<GLint>* _length);
+
    private:
     bool OffsetSizeValid(size_t offset, size_t size) const {
       size_t temp = offset + size;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 9b8e635..52a9c43 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1684,6 +1684,11 @@
            surface_->DeferDraws();
   }
 
+  bool IsRobustnessSupported() {
+    return has_robustness_extension_ &&
+           context_->WasAllocatedUsingRobustnessExtension();
+  }
+
   error::Error WillAccessBoundFramebufferForDraw() {
     if (ShouldDeferDraws())
       return error::kDeferCommandUntilLater;
@@ -1820,8 +1825,8 @@
   error::Error current_decoder_error_;
 
   bool use_shader_translator_;
-  scoped_refptr<ShaderTranslator> vertex_translator_;
-  scoped_refptr<ShaderTranslator> fragment_translator_;
+  scoped_refptr<ShaderTranslatorInterface> vertex_translator_;
+  scoped_refptr<ShaderTranslatorInterface> fragment_translator_;
 
   DisallowedFeatures disallowed_features_;
 
@@ -5837,15 +5842,7 @@
   }
 
   LogClientServiceForInfo(program, program_id, "glLinkProgram");
-  ShaderTranslator* vertex_translator = NULL;
-  ShaderTranslator* fragment_translator = NULL;
-  if (use_shader_translator_) {
-    vertex_translator = vertex_translator_.get();
-    fragment_translator = fragment_translator_.get();
-  }
   if (program->Link(shader_manager(),
-                    vertex_translator,
-                    fragment_translator,
                     workarounds().count_all_in_varyings_packing ?
                         Program::kCountAll : Program::kCountOnlyStaticallyUsed,
                     shader_cache_callback_)) {
@@ -7091,24 +7088,17 @@
   if (!shader) {
     return;
   }
-  ShaderTranslator* translator = NULL;
+
+  scoped_refptr<ShaderTranslatorInterface> translator;
   if (use_shader_translator_) {
-    translator = shader->shader_type() == GL_VERTEX_SHADER ?
-        vertex_translator_.get() : fragment_translator_.get();
+      translator = shader->shader_type() == GL_VERTEX_SHADER ?
+                   vertex_translator_ : fragment_translator_;
   }
 
-  shader->RequestCompile();
-
-  // TODO(dyen): Currently we compile immediately when glCompileShader is
-  // requested. Eventually this should be deffered to the linker stage.
-  shader->DoCompile(
-     translator,
-     feature_info_->feature_flags().angle_translated_shader_source ?
-         Shader::kANGLE : Shader::kGL);
-
-  // CompileShader can be very slow.  Exit command processing to allow for
-  // context preemption and GPU watchdog checks.
-  ExitCommandProcessingEarly();
+  const Shader::TranslatedShaderSourceType source_type =
+      feature_info_->feature_flags().angle_translated_shader_source ?
+      Shader::kANGLE : Shader::kGL;
+  shader->RequestCompile(translator, source_type);
 }
 
 void GLES2DecoderImpl::DoGetShaderiv(
@@ -7117,6 +7107,19 @@
   if (!shader) {
     return;
   }
+
+  // Compile now for statuses that require it.
+  switch (pname) {
+    case GL_COMPILE_STATUS:
+    case GL_INFO_LOG_LENGTH:
+    case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
+      shader->DoCompile();
+      break;
+
+    default:
+    break;
+  }
+
   switch (pname) {
     case GL_SHADER_SOURCE_LENGTH:
       *params = shader->source().size();
@@ -7174,6 +7177,9 @@
     return error::kNoError;
   }
 
+  // Make sure translator has been utilized in compile.
+  shader->DoCompile();
+
   bucket->SetFromString(shader->translated_source().c_str());
   return error::kNoError;
 }
@@ -7209,6 +7215,10 @@
     bucket->SetFromString("");
     return error::kNoError;
   }
+
+  // Shader must be compiled in order to get the info log.
+  shader->DoCompile();
+
   bucket->SetFromString(shader->log_info().c_str());
   return error::kNoError;
 }
@@ -8160,6 +8170,58 @@
     c.program, c.location_shm_id, c.location_shm_offset, name_str);
 }
 
+error::Error GLES2DecoderImpl::HandleGetUniformIndices(
+    uint32 immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetUniformIndices& c =
+      *static_cast<const gles2::cmds::GetUniformIndices*>(cmd_data);
+  Bucket* bucket = GetBucket(c.names_bucket_id);
+  if (!bucket) {
+    return error::kInvalidArguments;
+  }
+  GLsizei count = 0;
+  std::vector<char*> names;
+  std::vector<GLint> len;
+  if (!bucket->GetAsStrings(&count, &names, &len) || count <= 0) {
+    return error::kInvalidArguments;
+  }
+  typedef cmds::GetUniformIndices::Result Result;
+  Result* result = GetSharedMemoryAs<Result*>(
+      c.indices_shm_id, c.indices_shm_offset,
+      Result::ComputeSize(static_cast<size_t>(count)));
+  GLuint* indices = result ? result->GetData() : NULL;
+  if (indices == NULL) {
+    return error::kOutOfBounds;
+  }
+  // Check that the client initialized the result.
+  if (result->size != 0) {
+    return error::kInvalidArguments;
+  }
+  Program* program = GetProgramInfoNotShader(c.program, "glGetUniformIndices");
+  if (!program) {
+    return error::kNoError;
+  }
+  GLuint service_id = program->service_id();
+  GLint link_status = GL_FALSE;
+  glGetProgramiv(service_id, GL_LINK_STATUS, &link_status);
+  if (link_status != GL_TRUE) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+        "glGetUniformIndices", "program not linked");
+    return error::kNoError;
+  }
+  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetUniformIndices");
+  glGetUniformIndices(service_id, count, &names[0], indices);
+  GLenum error = glGetError();
+  if (error == GL_NO_ERROR) {
+    result->SetNumResults(count);
+  } else {
+    LOCAL_SET_GL_ERROR(error, "GetUniformIndices", "");
+  }
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::GetFragDataLocationHelper(
     GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
     const std::string& name_str) {
@@ -9730,6 +9792,63 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGetActiveUniformBlockiv(
+    uint32 immediate_data_size, const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetActiveUniformBlockiv& c =
+      *static_cast<const gles2::cmds::GetActiveUniformBlockiv*>(cmd_data);
+  GLuint program_id = c.program;
+  GLuint index = static_cast<GLuint>(c.index);
+  GLenum pname = static_cast<GLenum>(c.pname);
+  Program* program = GetProgramInfoNotShader(
+      program_id, "glGetActiveUniformBlockiv");
+  if (!program) {
+    return error::kNoError;
+  }
+  GLuint service_id = program->service_id();
+  GLint link_status = GL_FALSE;
+  glGetProgramiv(service_id, GL_LINK_STATUS, &link_status);
+  if (link_status != GL_TRUE) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+        "glGetActiveActiveUniformBlockiv", "program not linked");
+    return error::kNoError;
+  }
+  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetActiveUniformBlockiv");
+  GLsizei num_values = 1;
+  if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) {
+    GLint num = 0;
+    glGetActiveUniformBlockiv(
+        service_id, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &num);
+    GLenum error = glGetError();
+    if (error != GL_NO_ERROR) {
+      // Assume this will the same error if calling with pname.
+      LOCAL_SET_GL_ERROR(error, "GetActiveUniformBlockiv", "");
+      return error::kNoError;
+    }
+    num_values = static_cast<GLsizei>(num);
+  }
+  typedef cmds::GetActiveUniformBlockiv::Result Result;
+  Result* result = GetSharedMemoryAs<Result*>(
+      c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+  GLint* params = result ? result->GetData() : NULL;
+  if (params == NULL) {
+    return error::kOutOfBounds;
+  }
+  // Check that the client initialized the result.
+  if (result->size != 0) {
+    return error::kInvalidArguments;
+  }
+  glGetActiveUniformBlockiv(service_id, index, pname, params);
+  GLenum error = glGetError();
+  if (error == GL_NO_ERROR) {
+    result->SetNumResults(num_values);
+  } else {
+    LOCAL_SET_GL_ERROR(error, "GetActiveUniformBlockiv", "");
+  }
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleGetActiveUniformBlockName(
     uint32 immediate_data_size, const void* cmd_data) {
   if (!unsafe_es3_apis_enabled())
@@ -9783,6 +9902,55 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGetActiveUniformsiv(
+    uint32 immediate_data_size, const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetActiveUniformsiv& c =
+      *static_cast<const gles2::cmds::GetActiveUniformsiv*>(cmd_data);
+  GLuint program_id = c.program;
+  GLenum pname = static_cast<GLenum>(c.pname);
+  Bucket* bucket = GetBucket(c.indices_bucket_id);
+  if (!bucket) {
+    return error::kInvalidArguments;
+  }
+  GLsizei count = static_cast<GLsizei>(bucket->size() / sizeof(GLuint));
+  const GLuint* indices = bucket->GetDataAs<const GLuint*>(0, bucket->size());
+  typedef cmds::GetActiveUniformsiv::Result Result;
+  Result* result = GetSharedMemoryAs<Result*>(
+      c.params_shm_id, c.params_shm_offset, Result::ComputeSize(count));
+  GLint* params = result ? result->GetData() : NULL;
+  if (params == NULL) {
+    return error::kOutOfBounds;
+  }
+  // Check that the client initialized the result.
+  if (result->size != 0) {
+    return error::kInvalidArguments;
+  }
+  Program* program = GetProgramInfoNotShader(
+      program_id, "glGetActiveUniformsiv");
+  if (!program) {
+    return error::kNoError;
+  }
+  GLuint service_id = program->service_id();
+  GLint link_status = GL_FALSE;
+  glGetProgramiv(service_id, GL_LINK_STATUS, &link_status);
+  if (link_status != GL_TRUE) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+        "glGetActiveUniformsiv", "program not linked");
+    return error::kNoError;
+  }
+  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetActiveUniformsiv");
+  glGetActiveUniformsiv(service_id, count, indices, pname, params);
+  GLenum error = glGetError();
+  if (error == GL_NO_ERROR) {
+    result->SetNumResults(count);
+  } else {
+    LOCAL_SET_GL_ERROR(error, "GetActiveUniformsiv", "");
+  }
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleGetActiveAttrib(uint32 immediate_data_size,
                                                      const void* cmd_data) {
   const gles2::cmds::GetActiveAttrib& c =
@@ -10136,6 +10304,104 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGetUniformsES3CHROMIUM(
+    uint32 immediate_data_size, const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetUniformsES3CHROMIUM& c =
+      *static_cast<const gles2::cmds::GetUniformsES3CHROMIUM*>(cmd_data);
+  GLuint program_id = static_cast<GLuint>(c.program);
+  uint32 bucket_id = c.bucket_id;
+  Bucket* bucket = CreateBucket(bucket_id);
+  bucket->SetSize(sizeof(UniformsES3Header));  // in case we fail.
+  Program* program = NULL;
+  program = GetProgram(program_id);
+  if (!program || !program->IsValid()) {
+    return error::kNoError;
+  }
+  program->GetUniformsES3(bucket);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetTransformFeedbackVarying(
+    uint32 immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetTransformFeedbackVarying& c =
+      *static_cast<const gles2::cmds::GetTransformFeedbackVarying*>(cmd_data);
+  GLuint program_id = c.program;
+  GLuint index = c.index;
+  uint32 name_bucket_id = c.name_bucket_id;
+  typedef cmds::GetTransformFeedbackVarying::Result Result;
+  Result* result = GetSharedMemoryAs<Result*>(
+      c.result_shm_id, c.result_shm_offset, sizeof(*result));
+  if (!result) {
+    return error::kOutOfBounds;
+  }
+  // Check that the client initialized the result.
+  if (result->success != 0) {
+    return error::kInvalidArguments;
+  }
+  Program* program = GetProgramInfoNotShader(
+      program_id, "glGetTransformFeedbackVarying");
+  if (!program) {
+    return error::kNoError;
+  }
+  GLuint service_id = program->service_id();
+  GLint link_status = GL_FALSE;
+  glGetProgramiv(service_id, GL_LINK_STATUS, &link_status);
+  if (link_status != GL_TRUE) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+        "glGetTransformFeedbackVarying", "program not linked");
+    return error::kNoError;
+  }
+  GLint max_length = 0;
+  glGetProgramiv(
+      service_id, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &max_length);
+  max_length = std::max(1, max_length);
+  std::vector<char> buffer(max_length);
+  GLsizei length = 0;
+  GLsizei size = 0;
+  GLenum type = 0;
+  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetTransformFeedbackVarying");
+  glGetTransformFeedbackVarying(
+      service_id, index, max_length, &length, &size, &type, &buffer[0]);
+  GLenum error = glGetError();
+  if (error != GL_NO_ERROR) {
+    LOCAL_SET_GL_ERROR(error, "glGetTransformFeedbackVarying", "");
+    return error::kNoError;
+  }
+  result->success = 1;  // true.
+  result->size = static_cast<int32_t>(size);
+  result->type = static_cast<uint32_t>(type);
+  Bucket* bucket = CreateBucket(name_bucket_id);
+  DCHECK(length >= 0 && length < max_length);
+  buffer[length] = '\0';  // Just to be safe.
+  bucket->SetFromString(&buffer[0]);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetTransformFeedbackVaryingsCHROMIUM(
+    uint32 immediate_data_size, const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetTransformFeedbackVaryingsCHROMIUM& c =
+      *static_cast<const gles2::cmds::GetTransformFeedbackVaryingsCHROMIUM*>(
+          cmd_data);
+  GLuint program_id = static_cast<GLuint>(c.program);
+  uint32 bucket_id = c.bucket_id;
+  Bucket* bucket = CreateBucket(bucket_id);
+  bucket->SetSize(sizeof(TransformFeedbackVaryingsHeader));  // in case we fail.
+  Program* program = NULL;
+  program = GetProgram(program_id);
+  if (!program || !program->IsValid()) {
+    return error::kNoError;
+  }
+  program->GetTransformFeedbackVaryings(bucket);
+  return error::kNoError;
+}
+
 error::ContextLostReason GLES2DecoderImpl::GetContextLostReason() {
   switch (reset_status_) {
     case GL_NO_ERROR:
@@ -10172,10 +10438,8 @@
     MaybeExitOnContextLost();
     return true;
   }
-  if (context_->WasAllocatedUsingRobustnessExtension()) {
-    GLenum status = GL_NO_ERROR;
-    if (has_robustness_extension_)
-      status = glGetGraphicsResetStatusARB();
+  if (IsRobustnessSupported()) {
+    GLenum status = glGetGraphicsResetStatusARB();
     if (status != GL_NO_ERROR) {
       // The graphics card was reset. Signal a lost context to the application.
       reset_status_ = status;
@@ -10207,7 +10471,7 @@
       reset_status = GL_UNKNOWN_CONTEXT_RESET_ARB;
     }
   } else if (reset_status == GL_UNKNOWN_CONTEXT_RESET_ARB &&
-      has_robustness_extension_) {
+             IsRobustnessSupported()) {
     // If the reason for the call was a GL error, we can try to determine the
     // reset status more accurately.
     GLenum driver_status = glGetGraphicsResetStatusARB();
@@ -11772,6 +12036,25 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleUniformBlockBinding(
+    uint32_t immediate_data_size, const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::UniformBlockBinding& c =
+      *static_cast<const gles2::cmds::UniformBlockBinding*>(cmd_data);
+  GLuint client_id = c.program;
+  GLuint index = static_cast<GLuint>(c.index);
+  GLuint binding = static_cast<GLuint>(c.binding);
+  Program* program = GetProgramInfoNotShader(
+      client_id, "glUniformBlockBinding");
+  if (!program) {
+    return error::kNoError;
+  }
+  GLuint service_id = program->service_id();
+  glUniformBlockBinding(service_id, index, binding);
+  return error::kNoError;
+}
+
 void GLES2DecoderImpl::OnTextureRefDetachedFromFramebuffer(
     TextureRef* texture_ref) {
   Texture* texture = texture_ref->texture();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 720d54e..49fa872 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -2432,48 +2432,21 @@
   (void)c;
   GLuint shader = static_cast<GLuint>(c.shader);
 
-  const size_t kMinBucketSize = sizeof(GLint);
-  // Each string has at least |length| in the header and a NUL character.
-  const size_t kMinStringSize = sizeof(GLint) + 1;
   Bucket* bucket = GetBucket(c.str_bucket_id);
   if (!bucket) {
     return error::kInvalidArguments;
   }
-  const size_t bucket_size = bucket->size();
-  if (bucket_size < kMinBucketSize) {
+  GLsizei count = 0;
+  std::vector<char*> strs;
+  std::vector<GLint> len;
+  if (!bucket->GetAsStrings(&count, &strs, &len)) {
     return error::kInvalidArguments;
   }
-  const char* bucket_data = bucket->GetDataAs<const char*>(0, bucket_size);
-  const GLint* header = reinterpret_cast<const GLint*>(bucket_data);
-  GLsizei count = static_cast<GLsizei>(header[0]);
-  if (count < 0) {
-    return error::kInvalidArguments;
-  }
-  const size_t max_count = (bucket_size - kMinBucketSize) / kMinStringSize;
-  if (max_count < static_cast<size_t>(count)) {
-    return error::kInvalidArguments;
-  }
-  const GLint* length = header + 1;
-  scoped_ptr<const char* []> strs;
-  if (count > 0)
-    strs.reset(new const char* [count]);
-  const char** str = strs.get();
-  base::CheckedNumeric<size_t> total_size = sizeof(GLint);
-  total_size *= count + 1;  // Header size.
-  if (!total_size.IsValid())
-    return error::kInvalidArguments;
-  for (GLsizei ii = 0; ii < count; ++ii) {
-    str[ii] = bucket_data + total_size.ValueOrDefault(0);
-    total_size += length[ii];
-    total_size += 1;  // NUL char at the end of each char array.
-    if (!total_size.IsValid() || total_size.ValueOrDefault(0) > bucket_size ||
-        str[ii][length[ii]] != 0) {
-      return error::kInvalidArguments;
-    }
-  }
-  if (total_size.ValueOrDefault(0) != bucket_size) {
-    return error::kInvalidArguments;
-  }
+  const char** str =
+      strs.size() > 0 ? const_cast<const char**>(&strs[0]) : NULL;
+  const GLint* length =
+      len.size() > 0 ? const_cast<const GLint*>(&len[0]) : NULL;
+  (void)length;
   DoShaderSource(shader, count, str, length);
   return error::kNoError;
 }
@@ -2817,48 +2790,21 @@
   (void)c;
   GLuint program = static_cast<GLuint>(c.program);
 
-  const size_t kMinBucketSize = sizeof(GLint);
-  // Each string has at least |length| in the header and a NUL character.
-  const size_t kMinStringSize = sizeof(GLint) + 1;
   Bucket* bucket = GetBucket(c.varyings_bucket_id);
   if (!bucket) {
     return error::kInvalidArguments;
   }
-  const size_t bucket_size = bucket->size();
-  if (bucket_size < kMinBucketSize) {
+  GLsizei count = 0;
+  std::vector<char*> strs;
+  std::vector<GLint> len;
+  if (!bucket->GetAsStrings(&count, &strs, &len)) {
     return error::kInvalidArguments;
   }
-  const char* bucket_data = bucket->GetDataAs<const char*>(0, bucket_size);
-  const GLint* header = reinterpret_cast<const GLint*>(bucket_data);
-  GLsizei count = static_cast<GLsizei>(header[0]);
-  if (count < 0) {
-    return error::kInvalidArguments;
-  }
-  const size_t max_count = (bucket_size - kMinBucketSize) / kMinStringSize;
-  if (max_count < static_cast<size_t>(count)) {
-    return error::kInvalidArguments;
-  }
-  const GLint* length = header + 1;
-  scoped_ptr<const char* []> strs;
-  if (count > 0)
-    strs.reset(new const char* [count]);
-  const char** varyings = strs.get();
-  base::CheckedNumeric<size_t> total_size = sizeof(GLint);
-  total_size *= count + 1;  // Header size.
-  if (!total_size.IsValid())
-    return error::kInvalidArguments;
-  for (GLsizei ii = 0; ii < count; ++ii) {
-    varyings[ii] = bucket_data + total_size.ValueOrDefault(0);
-    total_size += length[ii];
-    total_size += 1;  // NUL char at the end of each char array.
-    if (!total_size.IsValid() || total_size.ValueOrDefault(0) > bucket_size ||
-        varyings[ii][length[ii]] != 0) {
-      return error::kInvalidArguments;
-    }
-  }
-  if (total_size.ValueOrDefault(0) != bucket_size) {
-    return error::kInvalidArguments;
-  }
+  const char** varyings =
+      strs.size() > 0 ? const_cast<const char**>(&strs[0]) : NULL;
+  const GLint* length =
+      len.size() > 0 ? const_cast<const GLint*>(&len[0]) : NULL;
+  (void)length;
   GLenum buffermode = static_cast<GLenum>(c.buffermode);
   DoTransformFeedbackVaryings(program, count, varyings, buffermode);
   return error::kNoError;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
index 381bb0c..80a0ce3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
@@ -248,7 +248,7 @@
   attach_cmd.Init(client_program_id_, kClientFragmentShaderId);
   EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
 
-  program->Link(NULL, NULL, NULL, Program::kCountOnlyStaticallyUsed,
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
                 base::Bind(&ShaderCacheCb));
 };
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
index 99f26e9..a255fe8 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -1208,8 +1208,12 @@
 
 // TODO(gman): GetActiveUniform
 
+// TODO(gman): GetActiveUniformBlockiv
+
 // TODO(gman): GetActiveUniformBlockName
 
+// TODO(gman): GetActiveUniformsiv
+
 // TODO(gman): GetAttachedShaders
 
 // TODO(gman): GetAttribLocation
@@ -1808,151 +1812,4 @@
 // TODO(gman): GetShaderSource
 // TODO(gman): GetString
 
-TEST_P(GLES2DecoderTest1, GetTexParameterfvValidArgs) {
-  EXPECT_CALL(*gl_, GetError())
-      .WillOnce(Return(GL_NO_ERROR))
-      .WillOnce(Return(GL_NO_ERROR))
-      .RetiresOnSaturation();
-  SpecializedSetup<cmds::GetTexParameterfv, 0>(true);
-  typedef cmds::GetTexParameterfv::Result Result;
-  Result* result = static_cast<Result*>(shared_memory_address_);
-  EXPECT_CALL(*gl_, GetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-                                      result->GetData()));
-  result->size = 0;
-  cmds::GetTexParameterfv cmd;
-  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
-           shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(
-      decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_TEXTURE_MAG_FILTER),
-      result->GetNumResults());
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterfvInvalidArgs0_0) {
-  EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
-  SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
-  cmds::GetTexParameterfv::Result* result =
-      static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
-  result->size = 0;
-  cmds::GetTexParameterfv cmd;
-  cmd.Init(GL_PROXY_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
-           shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(0u, result->size);
-  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterfvInvalidArgs1_0) {
-  EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
-  SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
-  cmds::GetTexParameterfv::Result* result =
-      static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
-  result->size = 0;
-  cmds::GetTexParameterfv cmd;
-  cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, shared_memory_id_,
-           shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(0u, result->size);
-  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterfvInvalidArgs2_0) {
-  EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
-  SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
-  cmds::GetTexParameterfv::Result* result =
-      static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
-  result->size = 0;
-  cmds::GetTexParameterfv cmd;
-  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, kInvalidSharedMemoryId, 0);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(0u, result->size);
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterfvInvalidArgs2_1) {
-  EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
-  SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
-  cmds::GetTexParameterfv::Result* result =
-      static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
-  result->size = 0;
-  cmds::GetTexParameterfv cmd;
-  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
-           kInvalidSharedMemoryOffset);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(0u, result->size);
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterivValidArgs) {
-  EXPECT_CALL(*gl_, GetError())
-      .WillOnce(Return(GL_NO_ERROR))
-      .WillOnce(Return(GL_NO_ERROR))
-      .RetiresOnSaturation();
-  SpecializedSetup<cmds::GetTexParameteriv, 0>(true);
-  typedef cmds::GetTexParameteriv::Result Result;
-  Result* result = static_cast<Result*>(shared_memory_address_);
-  EXPECT_CALL(*gl_, GetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-                                      result->GetData()));
-  result->size = 0;
-  cmds::GetTexParameteriv cmd;
-  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
-           shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(
-      decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_TEXTURE_MAG_FILTER),
-      result->GetNumResults());
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterivInvalidArgs0_0) {
-  EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
-  SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
-  cmds::GetTexParameteriv::Result* result =
-      static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
-  result->size = 0;
-  cmds::GetTexParameteriv cmd;
-  cmd.Init(GL_PROXY_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
-           shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(0u, result->size);
-  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterivInvalidArgs1_0) {
-  EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
-  SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
-  cmds::GetTexParameteriv::Result* result =
-      static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
-  result->size = 0;
-  cmds::GetTexParameteriv cmd;
-  cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, shared_memory_id_,
-           shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(0u, result->size);
-  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterivInvalidArgs2_0) {
-  EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
-  SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
-  cmds::GetTexParameteriv::Result* result =
-      static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
-  result->size = 0;
-  cmds::GetTexParameteriv cmd;
-  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, kInvalidSharedMemoryId, 0);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(0u, result->size);
-}
-
-TEST_P(GLES2DecoderTest1, GetTexParameterivInvalidArgs2_1) {
-  EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
-  SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
-  cmds::GetTexParameteriv::Result* result =
-      static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
-  result->size = 0;
-  cmds::GetTexParameteriv cmd;
-  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
-           kInvalidSharedMemoryOffset);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(0u, result->size);
-}
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
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 60d147b..2e60219 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
@@ -12,12 +12,163 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
 
+TEST_P(GLES2DecoderTest2, GetTexParameterfvValidArgs) {
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  SpecializedSetup<cmds::GetTexParameterfv, 0>(true);
+  typedef cmds::GetTexParameterfv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  EXPECT_CALL(*gl_, GetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+                                      result->GetData()));
+  result->size = 0;
+  cmds::GetTexParameterfv cmd;
+  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(
+      decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_TEXTURE_MAG_FILTER),
+      result->GetNumResults());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterfvInvalidArgs0_0) {
+  EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
+  SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
+  cmds::GetTexParameterfv::Result* result =
+      static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
+  result->size = 0;
+  cmds::GetTexParameterfv cmd;
+  cmd.Init(GL_PROXY_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0u, result->size);
+  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterfvInvalidArgs1_0) {
+  EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
+  SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
+  cmds::GetTexParameterfv::Result* result =
+      static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
+  result->size = 0;
+  cmds::GetTexParameterfv cmd;
+  cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0u, result->size);
+  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterfvInvalidArgs2_0) {
+  EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
+  SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
+  cmds::GetTexParameterfv::Result* result =
+      static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
+  result->size = 0;
+  cmds::GetTexParameterfv cmd;
+  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, kInvalidSharedMemoryId, 0);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  EXPECT_EQ(0u, result->size);
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterfvInvalidArgs2_1) {
+  EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
+  SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
+  cmds::GetTexParameterfv::Result* result =
+      static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
+  result->size = 0;
+  cmds::GetTexParameterfv cmd;
+  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  EXPECT_EQ(0u, result->size);
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterivValidArgs) {
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  SpecializedSetup<cmds::GetTexParameteriv, 0>(true);
+  typedef cmds::GetTexParameteriv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  EXPECT_CALL(*gl_, GetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+                                      result->GetData()));
+  result->size = 0;
+  cmds::GetTexParameteriv cmd;
+  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(
+      decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_TEXTURE_MAG_FILTER),
+      result->GetNumResults());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterivInvalidArgs0_0) {
+  EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
+  SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
+  cmds::GetTexParameteriv::Result* result =
+      static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
+  result->size = 0;
+  cmds::GetTexParameteriv cmd;
+  cmd.Init(GL_PROXY_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0u, result->size);
+  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterivInvalidArgs1_0) {
+  EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
+  SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
+  cmds::GetTexParameteriv::Result* result =
+      static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
+  result->size = 0;
+  cmds::GetTexParameteriv cmd;
+  cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0u, result->size);
+  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterivInvalidArgs2_0) {
+  EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
+  SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
+  cmds::GetTexParameteriv::Result* result =
+      static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
+  result->size = 0;
+  cmds::GetTexParameteriv cmd;
+  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, kInvalidSharedMemoryId, 0);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  EXPECT_EQ(0u, result->size);
+}
+
+TEST_P(GLES2DecoderTest2, GetTexParameterivInvalidArgs2_1) {
+  EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
+  SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
+  cmds::GetTexParameteriv::Result* result =
+      static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
+  result->size = 0;
+  cmds::GetTexParameteriv cmd;
+  cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  EXPECT_EQ(0u, result->size);
+}
+// TODO(gman): GetTransformFeedbackVarying
+
 // TODO(gman): GetUniformBlockIndex
 
 // TODO(gman): GetUniformfv
 
 // TODO(gman): GetUniformiv
 
+// TODO(gman): GetUniformIndices
+
 // TODO(gman): GetUniformLocation
 
 TEST_P(GLES2DecoderTest2, GetVertexAttribfvValidArgs) {
@@ -1217,6 +1368,7 @@
   decoder_->set_unsafe_es3_apis_enabled(false);
   EXPECT_EQ(error::kUnknownCommand, ExecuteImmediateCmd(cmd, sizeof(temp)));
 }
+// TODO(gman): UniformBlockBinding
 
 TEST_P(GLES2DecoderTest2, UniformMatrix2fvImmediateValidArgs) {
   cmds::UniformMatrix2fvImmediate& cmd =
@@ -1443,62 +1595,4 @@
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 }
-
-TEST_P(GLES2DecoderTest2, VertexAttrib3fValidArgs) {
-  EXPECT_CALL(*gl_, VertexAttrib3f(1, 2, 3, 4));
-  SpecializedSetup<cmds::VertexAttrib3f, 0>(true);
-  cmds::VertexAttrib3f cmd;
-  cmd.Init(1, 2, 3, 4);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest2, VertexAttrib3fvImmediateValidArgs) {
-  cmds::VertexAttrib3fvImmediate& cmd =
-      *GetImmediateAs<cmds::VertexAttrib3fvImmediate>();
-  SpecializedSetup<cmds::VertexAttrib3fvImmediate, 0>(true);
-  GLfloat temp[3] = {
-      0,
-  };
-  cmd.Init(1, &temp[0]);
-  EXPECT_CALL(*gl_, VertexAttrib3fv(1, reinterpret_cast<GLfloat*>(
-                                           ImmediateDataAddress(&cmd))));
-  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest2, VertexAttrib4fValidArgs) {
-  EXPECT_CALL(*gl_, VertexAttrib4f(1, 2, 3, 4, 5));
-  SpecializedSetup<cmds::VertexAttrib4f, 0>(true);
-  cmds::VertexAttrib4f cmd;
-  cmd.Init(1, 2, 3, 4, 5);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest2, VertexAttrib4fvImmediateValidArgs) {
-  cmds::VertexAttrib4fvImmediate& cmd =
-      *GetImmediateAs<cmds::VertexAttrib4fvImmediate>();
-  SpecializedSetup<cmds::VertexAttrib4fvImmediate, 0>(true);
-  GLfloat temp[4] = {
-      0,
-  };
-  cmd.Init(1, &temp[0]);
-  EXPECT_CALL(*gl_, VertexAttrib4fv(1, reinterpret_cast<GLfloat*>(
-                                           ImmediateDataAddress(&cmd))));
-  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest2, VertexAttribI4iValidArgs) {
-  EXPECT_CALL(*gl_, VertexAttribI4i(1, 2, 3, 4, 5));
-  SpecializedSetup<cmds::VertexAttribI4i, 0>(true);
-  cmds::VertexAttribI4i cmd;
-  cmd.Init(1, 2, 3, 4, 5);
-  decoder_->set_unsafe_es3_apis_enabled(true);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  decoder_->set_unsafe_es3_apis_enabled(false);
-  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
-}
 #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 6421985..7a58038 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,6 +12,64 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
 
+TEST_P(GLES2DecoderTest3, VertexAttrib3fValidArgs) {
+  EXPECT_CALL(*gl_, VertexAttrib3f(1, 2, 3, 4));
+  SpecializedSetup<cmds::VertexAttrib3f, 0>(true);
+  cmds::VertexAttrib3f cmd;
+  cmd.Init(1, 2, 3, 4);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest3, VertexAttrib3fvImmediateValidArgs) {
+  cmds::VertexAttrib3fvImmediate& cmd =
+      *GetImmediateAs<cmds::VertexAttrib3fvImmediate>();
+  SpecializedSetup<cmds::VertexAttrib3fvImmediate, 0>(true);
+  GLfloat temp[3] = {
+      0,
+  };
+  cmd.Init(1, &temp[0]);
+  EXPECT_CALL(*gl_, VertexAttrib3fv(1, reinterpret_cast<GLfloat*>(
+                                           ImmediateDataAddress(&cmd))));
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest3, VertexAttrib4fValidArgs) {
+  EXPECT_CALL(*gl_, VertexAttrib4f(1, 2, 3, 4, 5));
+  SpecializedSetup<cmds::VertexAttrib4f, 0>(true);
+  cmds::VertexAttrib4f cmd;
+  cmd.Init(1, 2, 3, 4, 5);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest3, VertexAttrib4fvImmediateValidArgs) {
+  cmds::VertexAttrib4fvImmediate& cmd =
+      *GetImmediateAs<cmds::VertexAttrib4fvImmediate>();
+  SpecializedSetup<cmds::VertexAttrib4fvImmediate, 0>(true);
+  GLfloat temp[4] = {
+      0,
+  };
+  cmd.Init(1, &temp[0]);
+  EXPECT_CALL(*gl_, VertexAttrib4fv(1, reinterpret_cast<GLfloat*>(
+                                           ImmediateDataAddress(&cmd))));
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest3, VertexAttribI4iValidArgs) {
+  EXPECT_CALL(*gl_, VertexAttribI4i(1, 2, 3, 4, 5));
+  SpecializedSetup<cmds::VertexAttribI4i, 0>(true);
+  cmds::VertexAttribI4i cmd;
+  cmd.Init(1, 2, 3, 4, 5);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderTest3, VertexAttribI4ivImmediateValidArgs) {
   cmds::VertexAttribI4ivImmediate& cmd =
       *GetImmediateAs<cmds::VertexAttribI4ivImmediate>();
@@ -144,6 +202,10 @@
 
 // TODO(gman): GetUniformBlocksCHROMIUM
 
+// TODO(gman): GetTransformFeedbackVaryingsCHROMIUM
+
+// TODO(gman): GetUniformsES3CHROMIUM
+
 // TODO(gman): GetTranslatedShaderSourceANGLE
 // TODO(gman): PostSubBufferCHROMIUM
 // TODO(gman): TexImageIOSurface2DCHROMIUM
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 807d488..c3fc9ff 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -570,21 +570,26 @@
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
 }
 
-void GLES2DecoderTestBase::SetBucketAsCString(
-    uint32 bucket_id, const char* str) {
-  uint32 size = str ? (strlen(str) + 1) : 0;
+void GLES2DecoderTestBase::SetBucketData(
+    uint32_t bucket_id, const void* data, uint32_t data_size) {
+  DCHECK(data || data_size == 0);
   cmd::SetBucketSize cmd1;
-  cmd1.Init(bucket_id, size);
+  cmd1.Init(bucket_id, data_size);
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
-  if (str) {
-    memcpy(shared_memory_address_, str, size);
+  if (data) {
+    memcpy(shared_memory_address_, data, data_size);
     cmd::SetBucketData cmd2;
-    cmd2.Init(bucket_id, 0, size, kSharedMemoryId, kSharedMemoryOffset);
+    cmd2.Init(bucket_id, 0, data_size, kSharedMemoryId, kSharedMemoryOffset);
     EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
     ClearSharedMemory();
   }
 }
 
+void GLES2DecoderTestBase::SetBucketAsCString(
+    uint32 bucket_id, const char* str) {
+  SetBucketData(bucket_id, str, str ? (strlen(str) + 1) : 0);
+}
+
 void GLES2DecoderTestBase::SetBucketAsCStrings(
     uint32 bucket_id, GLsizei count, const char** str,
     GLsizei count_in_header, char str_end) {
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 3159483..2160174 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -170,6 +170,7 @@
   void DoCreateShader(GLenum shader_type, GLuint client_id, GLuint service_id);
   void DoFenceSync(GLuint client_id, GLuint service_id);
 
+  void SetBucketData(uint32_t bucket_id, const void* data, uint32_t data_size);
   void SetBucketAsCString(uint32 bucket_id, const char* str);
   // If we want a valid bucket, just set |count_in_header| as |count|,
   // and set |str_end| as 0.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
index c0e2364..afb9fc7 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
@@ -43,7 +43,6 @@
 using ::testing::Return;
 using ::testing::SaveArg;
 using ::testing::SetArrayArgument;
-using ::testing::SetArgumentPointee;
 using ::testing::SetArgPointee;
 using ::testing::StrEq;
 using ::testing::StrictMock;
@@ -122,6 +121,93 @@
   EXPECT_EQ(0u, header->num_uniform_blocks);
 }
 
+TEST_P(GLES2DecoderWithShaderTest, GetUniformsES3CHROMIUMValidArgs) {
+  const uint32 kBucketId = 123;
+  GetUniformsES3CHROMIUM cmd;
+  cmd.Init(client_program_id_, kBucketId);
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_,
+              GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORMS, _))
+      .WillOnce(SetArgPointee<2>(0))
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+  EXPECT_EQ(sizeof(UniformsES3Header), bucket->size());
+  UniformsES3Header* header =
+      bucket->GetDataAs<UniformsES3Header*>(0, sizeof(UniformsES3Header));
+  EXPECT_TRUE(header != NULL);
+  EXPECT_EQ(0u, header->num_uniforms);
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetUniformsES3CHROMIUMInvalidArgs) {
+  const uint32 kBucketId = 123;
+  CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+  EXPECT_TRUE(bucket == NULL);
+  GetUniformsES3CHROMIUM cmd;
+  cmd.Init(kInvalidClientId, kBucketId);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  bucket = decoder_->GetBucket(kBucketId);
+  ASSERT_TRUE(bucket != NULL);
+  EXPECT_EQ(sizeof(UniformsES3Header), bucket->size());
+  UniformsES3Header* header =
+      bucket->GetDataAs<UniformsES3Header*>(0, sizeof(UniformsES3Header));
+  ASSERT_TRUE(header != NULL);
+  EXPECT_EQ(0u, header->num_uniforms);
+}
+
+TEST_P(GLES2DecoderWithShaderTest,
+       GetTransformFeedbackVaryingsCHROMIUMValidArgs) {
+  const uint32 kBucketId = 123;
+  GetTransformFeedbackVaryingsCHROMIUM cmd;
+  cmd.Init(client_program_id_, kBucketId);
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_,
+              GetProgramiv(
+                  kServiceProgramId, GL_TRANSFORM_FEEDBACK_VARYINGS, _))
+      .WillOnce(SetArgPointee<2>(0))
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+  EXPECT_EQ(sizeof(TransformFeedbackVaryingsHeader), bucket->size());
+  TransformFeedbackVaryingsHeader* header =
+      bucket->GetDataAs<TransformFeedbackVaryingsHeader*>(
+          0, sizeof(TransformFeedbackVaryingsHeader));
+  EXPECT_TRUE(header != NULL);
+  EXPECT_EQ(0u, header->num_transform_feedback_varyings);
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest,
+       GetTransformFeedbackVaryingsCHROMIUMInvalidArgs) {
+  const uint32 kBucketId = 123;
+  CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+  EXPECT_TRUE(bucket == NULL);
+  GetTransformFeedbackVaryingsCHROMIUM cmd;
+  cmd.Init(kInvalidClientId, kBucketId);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  bucket = decoder_->GetBucket(kBucketId);
+  ASSERT_TRUE(bucket != NULL);
+  EXPECT_EQ(sizeof(TransformFeedbackVaryingsHeader), bucket->size());
+  TransformFeedbackVaryingsHeader* header =
+      bucket->GetDataAs<TransformFeedbackVaryingsHeader*>(
+          0, sizeof(TransformFeedbackVaryingsHeader));
+  ASSERT_TRUE(header != NULL);
+  EXPECT_EQ(0u, header->num_transform_feedback_varyings);
+}
+
 TEST_P(GLES2DecoderWithShaderTest, GetUniformivSucceeds) {
   GetUniformiv::Result* result =
       static_cast<GetUniformiv::Result*>(shared_memory_address_);
@@ -344,7 +430,7 @@
   Result* result = static_cast<Result*>(shared_memory_address_);
   result->size = 0;
   EXPECT_CALL(*gl_, GetAttachedShaders(kServiceProgramId, 1, _, _)).WillOnce(
-      DoAll(SetArgumentPointee<2>(1), SetArgumentPointee<3>(kServiceShaderId)));
+      DoAll(SetArgPointee<2>(1), SetArgPointee<3>(kServiceShaderId)));
   cmd.Init(client_program_id_,
            shared_memory_id_,
            shared_memory_offset_,
@@ -409,7 +495,7 @@
   const GLint precision = 16;
   EXPECT_CALL(*gl_, GetShaderPrecisionFormat(_, _, _, _))
       .WillOnce(DoAll(SetArrayArgument<2>(range, range + 2),
-                      SetArgumentPointee<3>(precision)))
+                      SetArgPointee<3>(precision)))
       .RetiresOnSaturation();
   cmd.Init(GL_VERTEX_SHADER,
            GL_HIGH_FLOAT,
@@ -681,6 +767,175 @@
   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
 }
 
+TEST_P(GLES2DecoderWithShaderTest, GetActiveUniformBlockivSucceeds) {
+  GetActiveUniformBlockiv cmd;
+  typedef GetActiveUniformBlockiv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  GLenum kPname[] {
+    GL_UNIFORM_BLOCK_BINDING,
+    GL_UNIFORM_BLOCK_DATA_SIZE,
+    GL_UNIFORM_BLOCK_NAME_LENGTH,
+    GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS,
+    GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
+    GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
+    GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER,
+  };
+  for (size_t ii = 0; ii < arraysize(kPname); ++ii) {
+    result->SetNumResults(0);
+    cmd.Init(client_program_id_,
+             0,
+             kPname[ii],
+             shared_memory_id_,
+             shared_memory_offset_);
+    EXPECT_CALL(*gl_, GetError())
+        .WillOnce(Return(GL_NO_ERROR))
+        .WillOnce(Return(GL_NO_ERROR))
+        .RetiresOnSaturation();
+    EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+        .WillOnce(SetArgPointee<2>(GL_TRUE))
+        .RetiresOnSaturation();
+    if (kPname[ii] == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) {
+      EXPECT_CALL(*gl_, GetError())
+          .WillOnce(Return(GL_NO_ERROR))
+          .RetiresOnSaturation();
+      EXPECT_CALL(*gl_,
+                  GetActiveUniformBlockiv(kServiceProgramId, 0,
+                      GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, _))
+          .WillOnce(SetArgPointee<3>(1))
+          .RetiresOnSaturation();
+    }
+    EXPECT_CALL(*gl_,
+                GetActiveUniformBlockiv(
+                    kServiceProgramId, 0, kPname[ii], _))
+        .WillOnce(SetArgPointee<3>(1976))
+        .RetiresOnSaturation();
+    decoder_->set_unsafe_es3_apis_enabled(true);
+    EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+    EXPECT_EQ(1, result->GetNumResults());
+    EXPECT_EQ(GL_NO_ERROR, GetGLError());
+    EXPECT_EQ(1976, result->GetData()[0]);
+    decoder_->set_unsafe_es3_apis_enabled(false);
+    EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+  }
+}
+
+TEST_P(GLES2DecoderWithShaderTest,
+       GetActiveUniformBlockivSucceedsZeroUniforms) {
+  GetActiveUniformBlockiv cmd;
+  typedef GetActiveUniformBlockiv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->SetNumResults(0);
+  cmd.Init(client_program_id_,
+           0,
+           GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
+           shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_,
+              GetActiveUniformBlockiv(
+                  kServiceProgramId, 0, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, _))
+      .WillOnce(SetArgPointee<3>(0))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_,
+              GetActiveUniformBlockiv(kServiceProgramId, 0,
+                  GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetActiveUniformBlockivUnlinkedProgram) {
+  GetActiveUniformBlockiv cmd;
+  typedef GetActiveUniformBlockiv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->SetNumResults(0);
+  cmd.Init(client_program_id_,
+           0,
+           GL_UNIFORM_BLOCK_BINDING,
+           shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_FALSE))
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest,
+       GetActiveUniformBlockivResultNotInitFails) {
+  GetActiveUniformBlockiv cmd;
+  typedef GetActiveUniformBlockiv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->SetNumResults(1);  // Should be initialized to 0.
+  cmd.Init(client_program_id_,
+           0,
+           GL_UNIFORM_BLOCK_BINDING,
+           shared_memory_id_,
+           shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetActiveUniformBlockivBadProgramFails) {
+  GetActiveUniformBlockiv cmd;
+  typedef GetActiveUniformBlockiv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->SetNumResults(0);
+  cmd.Init(kInvalidClientId,
+           0,
+           GL_UNIFORM_BLOCK_BINDING,
+           shared_memory_id_,
+           shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest,
+       GetActiveUniformBlockivBadSharedMemoryFails) {
+  GetActiveUniformBlockiv cmd;
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  cmd.Init(client_program_id_,
+           0,
+           GL_UNIFORM_BLOCK_BINDING,
+           kInvalidSharedMemoryId,
+           shared_memory_offset_);
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+  cmd.Init(client_program_id_,
+           0,
+           GL_UNIFORM_BLOCK_BINDING,
+           shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderWithShaderTest, GetActiveAttribSucceeds) {
   const GLuint kAttribIndex = 1;
   const uint32 kBucketId = 123;
@@ -782,6 +1037,306 @@
   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
 }
 
+TEST_P(GLES2DecoderWithShaderTest, GetUniformIndicesSucceeds) {
+  const uint32 kBucketId = 123;
+  const char kName0[] = "Cow";
+  const char kName1[] = "Chicken";
+  const char* kNames[] = { kName0, kName1 };
+  const size_t kCount = arraysize(kNames);
+  const char kValidStrEnd = 0;
+  const GLuint kIndices[] = { 1, 2 };
+  SetBucketAsCStrings(kBucketId, kCount, kNames, kCount, kValidStrEnd);
+  GetUniformIndices::Result* result =
+      static_cast<GetUniformIndices::Result*>(shared_memory_address_);
+  GetUniformIndices cmd;
+  cmd.Init(client_program_id_,
+           kBucketId,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  EXPECT_CALL(*gl_, GetUniformIndices(kServiceProgramId, kCount, _, _))
+      .WillOnce(SetArrayArgument<3>(kIndices, kIndices + kCount))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  result->size = 0;
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(kCount, static_cast<size_t>(result->GetNumResults()));
+  for (size_t ii = 0; ii < kCount; ++ii) {
+    EXPECT_EQ(kIndices[ii], result->GetData()[ii]);
+  }
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetUniformIndicesBadProgramFails) {
+  const uint32 kBucketId = 123;
+  const char kName0[] = "Cow";
+  const char kName1[] = "Chicken";
+  const char* kNames[] = { kName0, kName1 };
+  const size_t kCount = arraysize(kNames);
+  const char kValidStrEnd = 0;
+  SetBucketAsCStrings(kBucketId, kCount, kNames, kCount, kValidStrEnd);
+  GetUniformIndices::Result* result =
+      static_cast<GetUniformIndices::Result*>(shared_memory_address_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  GetUniformIndices cmd;
+  // None-existant program
+  cmd.Init(kInvalidClientId,
+           kBucketId,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  result->size = 0;
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+  // Unlinked program.
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_FALSE))
+      .RetiresOnSaturation();
+  cmd.Init(client_program_id_,
+           kBucketId,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  result->size = 0;
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetUniformIndicesBadParamsFails) {
+  const uint32 kBucketId = 123;
+  const char kName0[] = "Cow";
+  const char kName1[] = "Chicken";
+  const char* kNames[] = { kName0, kName1 };
+  const size_t kCount = arraysize(kNames);
+  const char kValidStrEnd = 0;
+  const GLuint kIndices[] = { 1, 2 };
+  SetBucketAsCStrings(kBucketId, kCount, kNames, kCount, kValidStrEnd);
+  GetUniformIndices::Result* result =
+      static_cast<GetUniformIndices::Result*>(shared_memory_address_);
+  GetUniformIndices cmd;
+  cmd.Init(client_program_id_,
+           kBucketId,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  EXPECT_CALL(*gl_, GetUniformIndices(kServiceProgramId, kCount, _, _))
+      .WillOnce(SetArrayArgument<3>(kIndices, kIndices + kCount))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_INVALID_VALUE))
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  result->size = 0;
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetUniformIndicesResultNotInitFails) {
+  const uint32 kBucketId = 123;
+  const char kName0[] = "Cow";
+  const char kName1[] = "Chicken";
+  const char* kNames[] = { kName0, kName1 };
+  const size_t kCount = arraysize(kNames);
+  const char kValidStrEnd = 0;
+  SetBucketAsCStrings(kBucketId, kCount, kNames, kCount, kValidStrEnd);
+  GetUniformIndices::Result* result =
+      static_cast<GetUniformIndices::Result*>(shared_memory_address_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  GetUniformIndices cmd;
+  result->size = 1976;  // Any value other than 0.
+  cmd.Init(kInvalidClientId,
+           kBucketId,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetUniformIndicesBadSharedMemoryFails) {
+  const uint32 kBucketId = 123;
+  const char kName0[] = "Cow";
+  const char kName1[] = "Chicken";
+  const char* kNames[] = { kName0, kName1 };
+  const size_t kCount = arraysize(kNames);
+  const char kValidStrEnd = 0;
+  SetBucketAsCStrings(kBucketId, kCount, kNames, kCount, kValidStrEnd);
+  GetUniformIndices::Result* result =
+      static_cast<GetUniformIndices::Result*>(shared_memory_address_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  GetUniformIndices cmd;
+  cmd.Init(client_program_id_,
+           kBucketId,
+           kInvalidSharedMemoryId,
+           kSharedMemoryOffset);
+  result->size = 0;
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+  cmd.Init(client_program_id_,
+           kBucketId,
+           kSharedMemoryId,
+           kInvalidSharedMemoryOffset);
+  result->size = 0;
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetActiveUniformsivSucceeds) {
+  const uint32 kBucketId = 123;
+  const GLuint kIndices[] = { 1, 2 };
+  const GLint kResults[] = { 1976, 321 };
+  const size_t kCount = arraysize(kIndices);
+  SetBucketData(kBucketId, kIndices, sizeof(GLuint) * kCount);
+  GetActiveUniformsiv::Result* result =
+      static_cast<GetActiveUniformsiv::Result*>(shared_memory_address_);
+  GetActiveUniformsiv cmd;
+  cmd.Init(client_program_id_,
+           kBucketId,
+           GL_UNIFORM_TYPE,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  EXPECT_CALL(*gl_,
+              GetActiveUniformsiv(
+                  kServiceProgramId, kCount, _, GL_UNIFORM_TYPE, _))
+      .WillOnce(SetArrayArgument<4>(kResults, kResults + kCount))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  result->size = 0;
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(kCount, static_cast<size_t>(result->GetNumResults()));
+  for (size_t ii = 0; ii < kCount; ++ii) {
+    EXPECT_EQ(kResults[ii], result->GetData()[ii]);
+  }
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetActiveUniformsivBadProgramFails) {
+  const uint32 kBucketId = 123;
+  const GLuint kIndices[] = { 1, 2 };
+  const size_t kCount = arraysize(kIndices);
+  SetBucketData(kBucketId, kIndices, sizeof(GLuint) * kCount);
+  GetActiveUniformsiv::Result* result =
+      static_cast<GetActiveUniformsiv::Result*>(shared_memory_address_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  GetActiveUniformsiv cmd;
+  // None-existant program
+  cmd.Init(kInvalidClientId,
+           kBucketId,
+           GL_UNIFORM_TYPE,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  result->size = 0;
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+  // Unlinked program.
+  cmd.Init(client_program_id_,
+           kBucketId,
+           GL_UNIFORM_TYPE,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_FALSE))
+      .RetiresOnSaturation();
+  result->size = 0;
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetActiveUniformsivBadParamsFails) {
+  const uint32 kBucketId = 123;
+  const GLuint kIndices[] = { 1, 2 };
+  const GLint kResults[] = { 1976, 321 };
+  const size_t kCount = arraysize(kIndices);
+  SetBucketData(kBucketId, kIndices, sizeof(GLuint) * kCount);
+  GetActiveUniformsiv::Result* result =
+      static_cast<GetActiveUniformsiv::Result*>(shared_memory_address_);
+  GetActiveUniformsiv cmd;
+  cmd.Init(client_program_id_,
+           kBucketId,
+           GL_UNIFORM_TYPE,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  EXPECT_CALL(*gl_,
+              GetActiveUniformsiv(
+                  kServiceProgramId, kCount, _, GL_UNIFORM_TYPE, _))
+      .WillOnce(SetArrayArgument<4>(kResults, kResults + kCount))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_INVALID_VALUE))
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  result->size = 0;
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->GetNumResults());
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetActiveUniformsivResultNotInitFails) {
+  const uint32 kBucketId = 123;
+  const GLuint kIndices[] = { 1, 2 };
+  const size_t kCount = arraysize(kIndices);
+  SetBucketData(kBucketId, kIndices, sizeof(GLuint) * kCount);
+  GetActiveUniformsiv::Result* result =
+      static_cast<GetActiveUniformsiv::Result*>(shared_memory_address_);
+  GetActiveUniformsiv cmd;
+  cmd.Init(client_program_id_,
+           kBucketId,
+           GL_UNIFORM_TYPE,
+           kSharedMemoryId,
+           kSharedMemoryOffset);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  result->size = 1976;  // Any value other than 0.
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetActiveUniformsivBadSharedMemoryFails) {
+  const uint32 kBucketId = 123;
+  const GLuint kIndices[] = { 1, 2 };
+  const size_t kCount = arraysize(kIndices);
+  SetBucketData(kBucketId, kIndices, sizeof(GLuint) * kCount);
+  GetActiveUniformsiv::Result* result =
+      static_cast<GetActiveUniformsiv::Result*>(shared_memory_address_);
+  GetActiveUniformsiv cmd;
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  result->size = 0;
+  cmd.Init(client_program_id_,
+           kBucketId,
+           GL_UNIFORM_TYPE,
+           kInvalidSharedMemoryId,
+           kSharedMemoryOffset);
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+  result->size = 0;
+  cmd.Init(client_program_id_,
+           kBucketId,
+           GL_UNIFORM_TYPE,
+           kSharedMemoryId,
+           kInvalidSharedMemoryOffset);
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderWithShaderTest, GetShaderInfoLogValidArgs) {
   const char* kInfo = "hello";
   const uint32 kBucketId = 123;
@@ -790,13 +1345,13 @@
   EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _));
   EXPECT_CALL(*gl_, CompileShader(kServiceShaderId));
   EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _))
-      .WillOnce(SetArgumentPointee<2>(GL_FALSE))
+      .WillOnce(SetArgPointee<2>(GL_FALSE))
       .RetiresOnSaturation();
   EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_INFO_LOG_LENGTH, _))
-      .WillOnce(SetArgumentPointee<2>(strlen(kInfo) + 1))
+      .WillOnce(SetArgPointee<2>(strlen(kInfo) + 1))
       .RetiresOnSaturation();
   EXPECT_CALL(*gl_, GetShaderInfoLog(kServiceShaderId, strlen(kInfo) + 1, _, _))
-      .WillOnce(DoAll(SetArgumentPointee<2>(strlen(kInfo)),
+      .WillOnce(DoAll(SetArgPointee<2>(strlen(kInfo)),
                       SetArrayArgument<3>(kInfo, kInfo + strlen(kInfo) + 1)));
   compile_cmd.Init(client_shader_id_);
   cmd.Init(client_shader_id_, kBucketId);
@@ -818,15 +1373,168 @@
   EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
 }
 
-TEST_P(GLES2DecoderTest, CompileShaderValidArgs) {
-  EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _));
-  EXPECT_CALL(*gl_, CompileShader(kServiceShaderId));
-  EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _))
-      .WillOnce(SetArgumentPointee<2>(GL_TRUE))
+TEST_P(GLES2DecoderWithShaderTest, GetTransformFeedbackVaryingSucceeds) {
+  const GLuint kIndex = 1;
+  const uint32 kBucketId = 123;
+  const char kName[] = "HolyCow";
+  const GLsizei kBufferSize = static_cast<GLsizei>(strlen(kName) + 1);
+  const GLsizei kSize = 2;
+  const GLenum kType = GL_FLOAT_VEC2;
+  GetTransformFeedbackVarying cmd;
+  typedef GetTransformFeedbackVarying::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->success = 0;
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
       .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId,
+                                 GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, _))
+      .WillOnce(SetArgPointee<2>(kBufferSize))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_,
+              GetTransformFeedbackVarying(
+                  kServiceProgramId, kIndex, _, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<3>(kBufferSize - 1),
+                      SetArgPointee<4>(kSize),
+                      SetArgPointee<5>(kType),
+                      SetArrayArgument<6>(kName, kName + kBufferSize)))
+      .RetiresOnSaturation();
+  cmd.Init(client_program_id_,
+           kIndex,
+           kBucketId,
+           shared_memory_id_,
+           shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_NE(0, result->success);
+  EXPECT_EQ(kSize, static_cast<GLsizei>(result->size));
+  EXPECT_EQ(kType, static_cast<GLenum>(result->type));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+  ASSERT_TRUE(bucket != NULL);
+  EXPECT_EQ(
+      0, memcmp(bucket->GetData(0, bucket->size()), kName, bucket->size()));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetTransformFeedbackVaryingNotInitFails) {
+  const GLuint kIndex = 1;
+  const uint32 kBucketId = 123;
+  GetTransformFeedbackVarying cmd;
+  typedef GetTransformFeedbackVarying::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->success = 1;
+  cmd.Init(client_program_id_,
+           kIndex,
+           kBucketId,
+           shared_memory_id_,
+           shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetTransformFeedbackVaryingBadProgramFails) {
+  const GLuint kIndex = 1;
+  const uint32 kBucketId = 123;
+  GetTransformFeedbackVarying cmd;
+  typedef GetTransformFeedbackVarying::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->success = 0;
+  cmd.Init(kInvalidClientId,
+           kIndex,
+           kBucketId,
+           shared_memory_id_,
+           shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->success);
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, GetTransformFeedbackVaryingBadParamsFails) {
+  const GLuint kIndex = 1;
+  const uint32 kBucketId = 123;
+  const GLsizei kBufferSize = 10;
+  GetTransformFeedbackVarying cmd;
+  typedef GetTransformFeedbackVarying::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->success = 0;
+  cmd.Init(client_program_id_,
+           kIndex,
+           kBucketId,
+           shared_memory_id_,
+           shared_memory_offset_);
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId,
+                                 GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, _))
+      .WillOnce(SetArgPointee<2>(kBufferSize))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_INVALID_VALUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_,
+              GetTransformFeedbackVarying(
+                  kServiceProgramId, kIndex, _, _, _, _, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(0, result->success);
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest,
+       GetTransformFeedbackVaryingBadSharedMemoryFails) {
+  const GLuint kIndex = 1;
+  const uint32 kBucketId = 123;
+  GetTransformFeedbackVarying cmd;
+  typedef GetTransformFeedbackVarying::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  result->success = 0;
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  cmd.Init(client_program_id_,
+           kIndex,
+           kBucketId,
+           kInvalidSharedMemoryId,
+           shared_memory_offset_);
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+  cmd.Init(client_program_id_,
+           kIndex,
+           kBucketId,
+           shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, CompileShaderValidArgs) {
+  // Compile shader should not actually call any GL calls yet.
   CompileShader cmd;
   cmd.Init(client_shader_id_);
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+
+  // Getting the shader compilation state should trigger the actual GL calls.
+  EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _));
+  EXPECT_CALL(*gl_, CompileShader(kServiceShaderId));
+  EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetError())
+        .WillOnce(Return(GL_NO_ERROR))
+        .WillOnce(Return(GL_NO_ERROR))
+        .RetiresOnSaturation();
+
+  GetShaderiv status_cmd;
+  status_cmd.Init(client_shader_id_, GL_COMPILE_STATUS,
+                  kSharedMemoryId, kSharedMemoryOffset);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(status_cmd));
 }
 
 TEST_P(GLES2DecoderTest, CompileShaderInvalidArgs) {
@@ -1178,6 +1886,18 @@
   EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
 }
 
+TEST_P(GLES2DecoderWithShaderTest, UniformBlockBindingValidArgs) {
+  EXPECT_CALL(*gl_, UniformBlockBinding(kServiceProgramId, 2, 3));
+  SpecializedSetup<cmds::UniformBlockBinding, 0>(true);
+  cmds::UniformBlockBinding cmd;
+  cmd.Init(client_program_id_, 2, 3);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderWithShaderTest, BindUniformLocationCHROMIUMBucket) {
   const uint32 kBucketId = 123;
   const GLint kLocation = 2;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index 6c9d377..27c61ad 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -78,6 +78,8 @@
 ValueValidator<GLenum> texture_wrap_mode;
 ValueValidator<GLenum> transform_feedback_bind_target;
 ValueValidator<GLenum> transform_feedback_primitive_mode;
+ValueValidator<GLenum> uniform_block_parameter;
+ValueValidator<GLenum> uniform_parameter;
 ValueValidator<GLenum> value_buffer_target;
 ValueValidator<GLint> vertex_attrib_size;
 ValueValidator<GLenum> vertex_attrib_type;
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 1f1211b..97c3cdd 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -552,6 +552,27 @@
     GL_TRIANGLES,
 };
 
+static const GLenum valid_uniform_block_parameter_table[] = {
+    GL_UNIFORM_BLOCK_BINDING,
+    GL_UNIFORM_BLOCK_DATA_SIZE,
+    GL_UNIFORM_BLOCK_NAME_LENGTH,
+    GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS,
+    GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
+    GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
+    GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER,
+};
+
+static const GLenum valid_uniform_parameter_table[] = {
+    GL_UNIFORM_SIZE,
+    GL_UNIFORM_TYPE,
+    GL_UNIFORM_NAME_LENGTH,
+    GL_UNIFORM_BLOCK_INDEX,
+    GL_UNIFORM_OFFSET,
+    GL_UNIFORM_ARRAY_STRIDE,
+    GL_UNIFORM_MATRIX_STRIDE,
+    GL_UNIFORM_IS_ROW_MAJOR,
+};
+
 static const GLenum valid_value_buffer_target_table[] = {
     GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
 };
@@ -698,6 +719,10 @@
       transform_feedback_primitive_mode(
           valid_transform_feedback_primitive_mode_table,
           arraysize(valid_transform_feedback_primitive_mode_table)),
+      uniform_block_parameter(valid_uniform_block_parameter_table,
+                              arraysize(valid_uniform_block_parameter_table)),
+      uniform_parameter(valid_uniform_parameter_table,
+                        arraysize(valid_uniform_parameter_table)),
       value_buffer_target(valid_value_buffer_target_table,
                           arraysize(valid_value_buffer_target_table)),
       vertex_attrib_size(valid_vertex_attrib_size_table,
diff --git a/gpu/command_buffer/service/gpu_service_test.cc b/gpu/command_buffer/service/gpu_service_test.cc
index 89740b9..d0b9117 100644
--- a/gpu/command_buffer/service/gpu_service_test.cc
+++ b/gpu/command_buffer/service/gpu_service_test.cc
@@ -51,5 +51,8 @@
   testing::Test::TearDown();
 }
 
+gfx::GLContext* GpuServiceTest::GetGLContext() {
+  return context_.get();
+}
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_service_test.h b/gpu/command_buffer/service/gpu_service_test.h
index 539d6ba..7c9c978 100644
--- a/gpu/command_buffer/service/gpu_service_test.h
+++ b/gpu/command_buffer/service/gpu_service_test.h
@@ -28,6 +28,7 @@
   void SetUpWithGLVersion(const char* gl_version, const char* gl_extensions);
   void SetUp() override;
   void TearDown() override;
+  gfx::GLContext* GetGLContext();
 
   scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
 
@@ -40,4 +41,4 @@
 }  // namespace gles2
 }  // namespace gpu
 
-#endif  // GPU_COMMAND_BUFFER_SERVICE_MAILBOX_SYNCHRONIZER_H_
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GPU_SERVICE_TEST_H_
diff --git a/gpu/command_buffer/service/gpu_state_tracer.cc b/gpu/command_buffer/service/gpu_state_tracer.cc
index 47938cc..9b8db2a 100644
--- a/gpu/command_buffer/service/gpu_state_tracer.cc
+++ b/gpu/command_buffer/service/gpu_state_tracer.cc
@@ -16,14 +16,14 @@
 
 const int kBytesPerPixel = 4;
 
-class Snapshot : public base::debug::ConvertableToTraceFormat {
+class Snapshot : public base::trace_event::ConvertableToTraceFormat {
  public:
   static scoped_refptr<Snapshot> Create(const ContextState* state);
 
   // Save a screenshot of the currently bound framebuffer.
   bool SaveScreenshot(const gfx::Size& size);
 
-  // base::debug::ConvertableToTraceFormat implementation.
+  // base::trace_event::ConvertableToTraceFormat implementation.
   void AppendAsTraceFormat(std::string* out) const override;
 
  private:
@@ -125,7 +125,7 @@
       TRACE_DISABLED_BY_DEFAULT("gpu.debug"),
       "gpu::State",
       state_,
-      scoped_refptr<base::debug::ConvertableToTraceFormat>(snapshot));
+      scoped_refptr<base::trace_event::ConvertableToTraceFormat>(snapshot));
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/gpu_timing.cc b/gpu/command_buffer/service/gpu_timing.cc
new file mode 100644
index 0000000..8716448
--- /dev/null
+++ b/gpu/command_buffer/service/gpu_timing.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gpu_timing.h"
+
+#include "base/time/time.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_version_info.h"
+
+namespace gpu {
+
+GPUTimer::GPUTimer(GPUTiming* gpu_timing) : gpu_timing_(gpu_timing) {
+  DCHECK(gpu_timing_);
+  memset(queries_, 0, sizeof(queries_));
+  glGenQueriesARB(2, queries_);
+}
+
+GPUTimer::~GPUTimer() {
+  glDeleteQueriesARB(2, queries_);
+}
+
+void GPUTimer::Start() {
+  // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
+  glQueryCounter(queries_[0], GL_TIMESTAMP);
+  offset_ = gpu_timing_->CalculateTimerOffset();
+}
+
+void GPUTimer::End() {
+  end_requested_ = true;
+  glQueryCounter(queries_[1], GL_TIMESTAMP);
+}
+
+bool GPUTimer::IsAvailable() {
+  if (!gpu_timing_->IsAvailable() || !end_requested_) {
+    return false;
+  }
+  GLint done = 0;
+  glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
+  return done != 0;
+}
+
+void GPUTimer::GetStartEndTimestamps(int64* start, int64* end) {
+  DCHECK(start && end);
+  DCHECK(IsAvailable());
+  GLuint64 begin_stamp = 0;
+  GLuint64 end_stamp = 0;
+  // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
+  // We need to detect if the end is less then the start and correct for the
+  // wrapping.
+  glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp);
+  glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp);
+
+  *start = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
+  *end = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
+}
+
+int64 GPUTimer::GetDeltaElapsed() {
+  int64 start = 0;
+  int64 end = 0;
+  GetStartEndTimestamps(&start, &end);
+  return end - start;
+}
+
+GPUTiming::GPUTiming() : cpu_time_for_testing_() {
+}
+
+GPUTiming::~GPUTiming() {
+}
+
+bool GPUTiming::Initialize(gfx::GLContext* gl_context) {
+  DCHECK(gl_context);
+  DCHECK_EQ(kTimerTypeInvalid, timer_type_);
+
+  const gfx::GLVersionInfo* version_info = gl_context->GetVersionInfo();
+  DCHECK(version_info);
+  if (version_info->is_es3 &&  // glGetInteger64v is supported under ES3.
+      gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) {
+    timer_type_ = kTimerTypeDisjoint;
+    return true;
+  } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) {
+    timer_type_ = kTimerTypeARB;
+    return true;
+  }
+  return false;
+}
+
+bool GPUTiming::IsAvailable() {
+  return timer_type_ != kTimerTypeInvalid;
+}
+
+const char* GPUTiming::GetTimerTypeName() const {
+  switch (timer_type_) {
+    case kTimerTypeDisjoint:
+      return "GL_EXT_disjoint_timer_query";
+    case kTimerTypeARB:
+      return "GL_ARB_timer_query";
+    default:
+      return "Unknown";
+  }
+}
+
+bool GPUTiming::CheckAndResetTimerErrors() {
+  if (timer_type_ == kTimerTypeDisjoint) {
+    GLint disjoint_value = 0;
+    glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
+    return disjoint_value != 0;
+  } else {
+    return false;
+  }
+}
+
+int64 GPUTiming::CalculateTimerOffset() {
+  if (!offset_valid_) {
+    GLint64 gl_now = 0;
+    glGetInteger64v(GL_TIMESTAMP, &gl_now);
+    int64 now =
+        cpu_time_for_testing_.is_null()
+            ? base::TimeTicks::NowFromSystemTraceTime().ToInternalValue()
+            : cpu_time_for_testing_.Run();
+    offset_ = now - gl_now / base::Time::kNanosecondsPerMicrosecond;
+    offset_valid_ = timer_type_ == kTimerTypeARB;
+  }
+  return offset_;
+}
+
+void GPUTiming::InvalidateTimerOffset() {
+  offset_valid_ = false;
+}
+
+void GPUTiming::SetCpuTimeForTesting(
+    const base::Callback<int64(void)>& cpu_time) {
+  cpu_time_for_testing_ = cpu_time;
+}
+
+void GPUTiming::SetOffsetForTesting(int64 offset, bool cache_it) {
+  offset_ = offset;
+  offset_valid_ = cache_it;
+}
+
+void GPUTiming::SetTimerTypeForTesting(TimerType type) {
+  timer_type_ = type;
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_timing.h b/gpu/command_buffer/service/gpu_timing.h
new file mode 100644
index 0000000..1d9ecf6
--- /dev/null
+++ b/gpu/command_buffer/service/gpu_timing.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_TIMING_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_TIMING_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/gpu_export.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace gpu {
+
+class GPUTiming;
+
+// Class to compute the amount of time it takes to fully
+// complete a set of GL commands
+class GPU_EXPORT GPUTimer {
+ public:
+  // gpu_timing must outlive GPUTimer instance we're creating.
+  explicit GPUTimer(GPUTiming* gpu_timing);
+  ~GPUTimer();
+
+  void Start();
+  void End();
+  bool IsAvailable();
+
+  void GetStartEndTimestamps(int64* start, int64* end);
+  int64 GetDeltaElapsed();
+
+ private:
+  GLuint queries_[2];
+  int64 offset_ = 0;
+  bool end_requested_ = false;
+  GPUTiming* gpu_timing_;
+
+  DISALLOW_COPY_AND_ASSIGN(GPUTimer);
+};
+
+// GPUTiming contains all the gl timing logic that is not specific
+// to a single GPUTimer.
+class GPU_EXPORT GPUTiming {
+ public:
+  enum TimerType {
+    kTimerTypeInvalid = -1,
+
+    kTimerTypeARB,      // ARB_timer_query
+    kTimerTypeDisjoint  // EXT_disjoint_timer_query
+  };
+
+  GPUTiming();
+  virtual ~GPUTiming();
+
+  bool Initialize(gfx::GLContext* context);
+  bool IsAvailable();
+
+  // CheckAndResetTimerErrors has to be called before reading timestamps
+  // from GPUTimers instances and after making sure all the timers
+  // were available.
+  // If the returned value is false, all the previous timers should be
+  // discarded.
+  bool CheckAndResetTimerErrors();
+
+  const char* GetTimerTypeName() const;
+
+  // Returns the offset between the current gpu time and the cpu time.
+  int64 CalculateTimerOffset();
+  void InvalidateTimerOffset();
+
+  void SetCpuTimeForTesting(const base::Callback<int64(void)>& cpu_time);
+  void SetOffsetForTesting(int64 offset, bool cache_it);
+  void SetTimerTypeForTesting(TimerType type);
+
+ private:
+  TimerType timer_type_ = kTimerTypeInvalid;
+  int64 offset_ = 0;  // offset cache when timer_type_ == kTimerTypeARB
+  bool offset_valid_ = false;
+  base::Callback<int64(void)> cpu_time_for_testing_;
+  friend class GPUTimer;
+  DISALLOW_COPY_AND_ASSIGN(GPUTiming);
+};
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GPU_TIMING_H_
diff --git a/gpu/command_buffer/service/gpu_tracer.cc b/gpu/command_buffer/service/gpu_tracer.cc
index 72b29dd..6bedb7f 100644
--- a/gpu/command_buffer/service/gpu_tracer.cc
+++ b/gpu/command_buffer/service/gpu_tracer.cc
@@ -20,16 +20,6 @@
 static const unsigned int kProcessInterval = 16;
 static TraceOutputter* g_outputter_thread = NULL;
 
-CPUTime::CPUTime() {
-}
-
-int64 CPUTime::GetCurrentTime() {
-  return base::TimeTicks::NowFromSystemTraceTime().ToInternalValue();
-}
-
-CPUTime::~CPUTime() {
-}
-
 TraceMarker::TraceMarker(const std::string& category, const std::string& name)
     : category_(category),
       name_(name),
@@ -90,122 +80,53 @@
 }
 
 GPUTrace::GPUTrace(scoped_refptr<Outputter> outputter,
-                   scoped_refptr<CPUTime> cpu_time,
+                   gpu::GPUTiming* gpu_timing,
                    const std::string& category,
                    const std::string& name,
-                   int64 offset,
-                   GpuTracerType tracer_type)
+                   const bool enabled)
     : category_(category),
       name_(name),
       outputter_(outputter),
-      cpu_time_(cpu_time),
-      offset_(offset),
-      start_time_(0),
-      end_time_(0),
-      tracer_type_(tracer_type),
-      end_requested_(false) {
-  memset(queries_, 0, sizeof(queries_));
-  switch (tracer_type_) {
-    case kTracerTypeARBTimer:
-    case kTracerTypeDisjointTimer:
-      glGenQueriesARB(2, queries_);
-      break;
-
-    default:
-      tracer_type_ = kTracerTypeInvalid;
+      enabled_(enabled) {
+  if (gpu_timing->IsAvailable()) {
+    gpu_timer_.reset(new GPUTimer(gpu_timing));
   }
 }
 
 GPUTrace::~GPUTrace() {
-  switch (tracer_type_) {
-    case kTracerTypeInvalid:
-      break;
-
-    case kTracerTypeARBTimer:
-    case kTracerTypeDisjointTimer:
-      glDeleteQueriesARB(2, queries_);
-      break;
-  }
 }
 
 void GPUTrace::Start(bool trace_service) {
   if (trace_service) {
     outputter_->TraceServiceBegin(category_, name_);
   }
-
-  switch (tracer_type_) {
-    case kTracerTypeInvalid:
-      break;
-
-    case kTracerTypeDisjointTimer:
-      // For the disjoint timer, GPU idle time does not seem to increment the
-      // internal counter. We must calculate the offset before any query.
-      // glGetInteger64v is supported under ES3 which we check for before using
-      // the kTracerTypeDisjointTimer.
-      {
-        GLint64 gl_now = 0;
-        glGetInteger64v(GL_TIMESTAMP, &gl_now);
-        offset_ = cpu_time_->GetCurrentTime() -
-                  gl_now / base::Time::kNanosecondsPerMicrosecond;
-      }
-      // Intentionally fall through to kTracerTypeARBTimer case.xs
-    case kTracerTypeARBTimer:
-      // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
-      glQueryCounter(queries_[0], GL_TIMESTAMP);
-      break;
+  if (gpu_timer_.get()) {
+    gpu_timer_->Start();
   }
 }
 
 void GPUTrace::End(bool tracing_service) {
-  end_requested_ = true;
-  switch (tracer_type_) {
-    case kTracerTypeInvalid:
-      break;
-
-    case kTracerTypeARBTimer:
-    case kTracerTypeDisjointTimer:
-      // GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
-      glQueryCounter(queries_[1], GL_TIMESTAMP);
-      break;
+  if (gpu_timer_.get()) {
+    gpu_timer_->End();
   }
-
   if (tracing_service) {
     outputter_->TraceServiceEnd(category_, name_);
   }
 }
 
 bool GPUTrace::IsAvailable() {
-  if (tracer_type_ != kTracerTypeInvalid) {
-    if (!end_requested_)
-      return false;
-
-    GLint done = 0;
-    glGetQueryObjectivARB(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
-    return !!done;
-  }
-
-  return true;
+  return !gpu_timer_.get() || gpu_timer_->IsAvailable();
 }
 
 void GPUTrace::Process() {
-  if (tracer_type_ == kTracerTypeInvalid)
-    return;
+  if (gpu_timer_.get()) {
+    DCHECK(IsAvailable());
 
-  DCHECK(IsAvailable());
-
-  GLuint64 begin_stamp = 0;
-  GLuint64 end_stamp = 0;
-
-  // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
-  // We need to detect if the end is less then the start and correct for the
-  // wrapping.
-  glGetQueryObjectui64v(queries_[0], GL_QUERY_RESULT, &begin_stamp);
-  glGetQueryObjectui64v(queries_[1], GL_QUERY_RESULT, &end_stamp);
-
-  start_time_ = (begin_stamp / base::Time::kNanosecondsPerMicrosecond) +
-                offset_;
-  end_time_ = (end_stamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
-  outputter_->TraceDevice(category_, name_, start_time_, end_time_);
+    int64 start = 0;
+    int64 end = 0;
+    gpu_timer_->GetStartEndTimestamps(&start, &end);
+    outputter_->TraceDevice(category_, name_, start, end);
+  }
 }
 
 GPUTracer::GPUTracer(gles2::GLES2Decoder* decoder)
@@ -214,9 +135,7 @@
       gpu_trace_dev_category(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
           TRACE_DISABLED_BY_DEFAULT("gpu.device"))),
       decoder_(decoder),
-      timer_offset_(0),
-      tracer_type_(kTracerTypeInvalid),
-      gpu_timing_synced_(false),
+      gpu_timing_(),
       gpu_executing_(false),
       process_posted_(false) {
 }
@@ -229,43 +148,25 @@
     return false;
 
   if (outputter_ == NULL) {
-    tracer_type_ = DetermineTracerType();
-    const char* tracer_type_name = "Unknown";
-    switch (tracer_type_) {
-      case kTracerTypeDisjointTimer:
-        tracer_type_name = "GL_EXT_disjoint_timer_query";
-        break;
-      case kTracerTypeARBTimer:
-        tracer_type_name = "GL_ARB_timer_query";
-        break;
-
-      default:
-        break;
-    }
-
-    outputter_ = CreateOutputter(tracer_type_name);
+    outputter_ = CreateOutputter(gpu_timing_.GetTimerTypeName());
+    gpu_timing_.Initialize(decoder_->GetGLContext());
   }
 
-  if (cpu_time_ == NULL) {
-    cpu_time_ = CreateCPUTime();
+  if (*gpu_trace_dev_category == '\0') {
+    // If GPU device category is off, invalidate timing sync.
+    gpu_timing_.InvalidateTimerOffset();
   }
 
-  CalculateTimerOffset();
   gpu_executing_ = true;
-
   if (IsTracing()) {
-    // Reset disjoint bit for the disjoint timer.
-    if (tracer_type_ == kTracerTypeDisjointTimer) {
-      GLint disjoint_value = 0;
-      glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
-    }
-
+    gpu_timing_.CheckAndResetTimerErrors();
     // Begin a Trace for all active markers
     for (int n = 0; n < NUM_TRACER_SOURCES; n++) {
       for (size_t i = 0; i < markers_[n].size(); i++) {
         TraceMarker& trace_marker = markers_[n][i];
-        trace_marker.trace_ = CreateTrace(trace_marker.category_,
-                                          trace_marker.name_);
+        trace_marker.trace_ =
+            new GPUTrace(outputter_, &gpu_timing_, trace_marker.category_,
+                         trace_marker.name_, *gpu_trace_dev_category != 0);
         trace_marker.trace_->Start(*gpu_trace_srv_category != 0);
       }
     }
@@ -313,7 +214,8 @@
 
   // Create trace
   if (IsTracing()) {
-    scoped_refptr<GPUTrace> trace = CreateTrace(category, name);
+    scoped_refptr<GPUTrace> trace = new GPUTrace(
+        outputter_, &gpu_timing_, category, name, *gpu_trace_dev_category != 0);
     trace->Start(*gpu_trace_srv_category != 0);
     markers_[source].back().trace_ = trace;
   }
@@ -367,38 +269,10 @@
   return base::EmptyString();
 }
 
-scoped_refptr<GPUTrace> GPUTracer::CreateTrace(const std::string& category,
-                                               const std::string& name) {
-  GpuTracerType tracer_type = *gpu_trace_dev_category ? tracer_type_ :
-                                                        kTracerTypeInvalid;
-
-  return new GPUTrace(outputter_, cpu_time_, category, name,
-                      timer_offset_, tracer_type);
-}
-
 scoped_refptr<Outputter> GPUTracer::CreateOutputter(const std::string& name) {
   return TraceOutputter::Create(name);
 }
 
-scoped_refptr<CPUTime> GPUTracer::CreateCPUTime() {
-  return new CPUTime();
-}
-
-GpuTracerType GPUTracer::DetermineTracerType() {
-  ContextGroup* context_group = decoder_->GetContextGroup();
-  const gpu::gles2::FeatureInfo* feature_info = context_group->feature_info();
-  const gfx::GLVersionInfo& version_info = feature_info->gl_version_info();
-
-  if (version_info.is_es3 &&
-      gfx::g_driver_gl.ext.b_GL_EXT_disjoint_timer_query) {
-    return kTracerTypeDisjointTimer;
-  } else if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query) {
-    return kTracerTypeARBTimer;
-  }
-
-  return kTracerTypeInvalid;
-}
-
 void GPUTracer::PostTask() {
   base::MessageLoop::current()->PostDelayedTask(
       FROM_HERE,
@@ -413,7 +287,7 @@
 }
 
 void GPUTracer::ProcessTraces() {
-  if (tracer_type_ == kTracerTypeInvalid) {
+  if (!gpu_timing_.IsAvailable()) {
     traces_.clear();
     return;
   }
@@ -427,13 +301,10 @@
     return;
   }
 
-  // Check if disjoint operation has occurred, discard ongoing traces if so.
-  if (tracer_type_ == kTracerTypeDisjointTimer) {
-    GLint disjoint_value = 0;
-    glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjoint_value);
-    if (disjoint_value)
-      traces_.clear();
-  }
+  // Check if timers are still valid (e.g: a disjoint operation
+  // might have occurred.)
+  if (gpu_timing_.CheckAndResetTimerErrors())
+    traces_.clear();
 
   while (!traces_.empty() && traces_.front()->IsAvailable()) {
     traces_.front()->Process();
@@ -446,24 +317,6 @@
     traces_.clear();
 }
 
-void GPUTracer::CalculateTimerOffset() {
-  if (tracer_type_ != kTracerTypeInvalid) {
-    if (*gpu_trace_dev_category == '\0') {
-      // If GPU device category is off, invalidate timing sync.
-      gpu_timing_synced_ = false;
-    } else if (!gpu_timing_synced_ && tracer_type_ == kTracerTypeARBTimer) {
-      TRACE_EVENT0("gpu", "GPUTracer::CalculateTimerOffset");
-
-      // ARB Timer is written for OpenGL 3.2 which contains glGetInteger64v().
-      GLint64 gl_now = 0;
-      glGetInteger64v(GL_TIMESTAMP, &gl_now);
-      timer_offset_ = cpu_time_->GetCurrentTime() -
-                      gl_now / base::Time::kNanosecondsPerMicrosecond;
-      gpu_timing_synced_ = true;
-    }
-  }
-}
-
 void GPUTracer::IssueProcessTask() {
   if (traces_.empty() || process_posted_)
     return;
diff --git a/gpu/command_buffer/service/gpu_tracer.h b/gpu/command_buffer/service/gpu_tracer.h
index 594a98e..c8ac9d7 100644
--- a/gpu/command_buffer/service/gpu_tracer.h
+++ b/gpu/command_buffer/service/gpu_tracer.h
@@ -6,13 +6,16 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_TRACER_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GPU_TRACER_H_
 
+#include <deque>
 #include <string>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gpu_timing.h"
 #include "gpu/gpu_export.h"
 #include "ui/gl/gl_bindings.h"
 
@@ -33,28 +36,6 @@
   NUM_TRACER_SOURCES
 };
 
-enum GpuTracerType {
-  kTracerTypeInvalid = -1,
-
-  kTracerTypeARBTimer,
-  kTracerTypeDisjointTimer
-};
-
-// Central accesser to CPU Time
-class GPU_EXPORT CPUTime
-    : public base::RefCounted<CPUTime> {
- public:
-  CPUTime();
-
-  virtual int64 GetCurrentTime();
-
- protected:
-  virtual ~CPUTime();
-  friend class base::RefCounted<CPUTime>;
-
-  DISALLOW_COPY_AND_ASSIGN(CPUTime);
-};
-
 // Marker structure for a Trace.
 struct TraceMarker {
   TraceMarker(const std::string& category, const std::string& name);
@@ -94,35 +75,27 @@
 
  protected:
   // Trace Processing.
-  scoped_refptr<GPUTrace> CreateTrace(const std::string& category,
-                                      const std::string& name);
   virtual scoped_refptr<Outputter> CreateOutputter(const std::string& name);
-  virtual scoped_refptr<CPUTime> CreateCPUTime();
-  virtual GpuTracerType DetermineTracerType();
   virtual void PostTask();
 
   void Process();
   void ProcessTraces();
 
-  void CalculateTimerOffset();
   void IssueProcessTask();
 
   scoped_refptr<Outputter> outputter_;
-  scoped_refptr<CPUTime> cpu_time_;
   std::vector<TraceMarker> markers_[NUM_TRACER_SOURCES];
   std::deque<scoped_refptr<GPUTrace> > traces_;
 
   const unsigned char* gpu_trace_srv_category;
   const unsigned char* gpu_trace_dev_category;
   gles2::GLES2Decoder* decoder_;
+  gpu::GPUTiming gpu_timing_;
 
-  int64 timer_offset_;
-
-  GpuTracerType tracer_type_;
-  bool gpu_timing_synced_;
   bool gpu_executing_;
   bool process_posted_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(GPUTracer);
 };
 
@@ -166,6 +139,7 @@
   base::Thread named_thread_;
   uint64 local_trace_id_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(TraceOutputter);
 };
 
@@ -173,17 +147,15 @@
     : public base::RefCounted<GPUTrace> {
  public:
   GPUTrace(scoped_refptr<Outputter> outputter,
-           scoped_refptr<CPUTime> cpu_time,
+           gpu::GPUTiming* gpu_timing,
            const std::string& category,
            const std::string& name,
-           int64 offset,
-           GpuTracerType tracer_type);
-
-  bool IsEnabled() { return tracer_type_ != kTracerTypeInvalid; }
+           const bool enabled);
 
   void Start(bool trace_service);
   void End(bool tracing_service);
   bool IsAvailable();
+  bool IsEnabled() { return enabled_; }
   void Process();
 
  private:
@@ -196,35 +168,27 @@
   std::string category_;
   std::string name_;
   scoped_refptr<Outputter> outputter_;
-  scoped_refptr<CPUTime> cpu_time_;
-
-  int64 offset_;
-  int64 start_time_;
-  int64 end_time_;
-  GpuTracerType tracer_type_;
-  bool end_requested_;
-
-  GLuint queries_[2];
+  scoped_ptr<gpu::GPUTimer> gpu_timer_;
+  const bool enabled_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(GPUTrace);
 };
 
 class ScopedGPUTrace {
-  public:
-    ScopedGPUTrace(GPUTracer* gpu_tracer, GpuTracerSource source,
-                   const std::string& category, const std::string& name)
-        : gpu_tracer_(gpu_tracer),
-          source_(source) {
-      gpu_tracer_->Begin(category, name, source_);
-    }
+ public:
+  ScopedGPUTrace(GPUTracer* gpu_tracer,
+                 GpuTracerSource source,
+                 const std::string& category,
+                 const std::string& name)
+      : gpu_tracer_(gpu_tracer), source_(source) {
+    gpu_tracer_->Begin(category, name, source_);
+  }
 
-    ~ScopedGPUTrace() {
-      gpu_tracer_->End(source_);
-    }
+  ~ScopedGPUTrace() { gpu_tracer_->End(source_); }
 
-   private:
-    GPUTracer* gpu_tracer_;
-    GpuTracerSource source_;
+ private:
+  GPUTracer* gpu_tracer_;
+  GpuTracerSource source_;
 };
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/gpu_tracer_unittest.cc b/gpu/command_buffer/service/gpu_tracer_unittest.cc
index 1b10fc6..9005421 100644
--- a/gpu/command_buffer/service/gpu_tracer_unittest.cc
+++ b/gpu/command_buffer/service/gpu_tracer_unittest.cc
@@ -5,43 +5,30 @@
 #include <map>
 #include <set>
 
+#include "base/bind.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
+#include "gpu/command_buffer/service/gpu_timing.h"
 #include "gpu/command_buffer/service/gpu_tracer.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gl/gl_context_stub.h"
 #include "ui/gl/gl_mock.h"
-#include "ui/gl/gl_surface_stub.h"
 
 namespace gpu {
 namespace gles2 {
+namespace {
 
 using ::testing::_;
 using ::testing::AtLeast;
+using ::testing::AtMost;
 using ::testing::Exactly;
 using ::testing::Invoke;
 using ::testing::NotNull;
 using ::testing::Return;
 
-class FakeCPUTime : public CPUTime {
- public:
-  FakeCPUTime()
-      : current_cpu_time_(0) {
-  }
-
-  int64 GetCurrentTime() override {
-    return current_cpu_time_;
-  }
-
-  void SetFakeCPUTime(int64 cpu_time) {
-    current_cpu_time_ = cpu_time;
-  }
-
- protected:
-  ~FakeCPUTime() override {}
-
-  int64 current_cpu_time_;
-};
+int64 g_fakeCPUTime = 0;
+int64 FakeCpuTime() {
+  return g_fakeCPUTime;
+}
 
 class MockOutputter : public Outputter {
  public:
@@ -154,19 +141,19 @@
   }
 
  protected:
-  bool disjointed_;
-  GLint64 current_time_;
-  GLuint next_query_id_;
+  bool disjointed_ = false;
+  GLint64 current_time_ = 0;
+  GLuint next_query_id_ = 0;
   std::set<GLuint> alloced_queries_;
   std::map<GLuint, GLint64> query_timestamp_;
 };
 
 class GPUTracerTester : public GPUTracer {
  public:
-  GPUTracerTester(GpuTracerType tracer_type, gles2::GLES2Decoder* decoder)
-      : GPUTracer(decoder),
-        tracing_enabled_(0),
-        test_tracer_type_(tracer_type) {
+  explicit GPUTracerTester(gles2::GLES2Decoder* decoder)
+      : GPUTracer(decoder), tracing_enabled_(0) {
+    gpu_timing_.SetCpuTimeForTesting(base::Bind(&FakeCpuTime));
+
     // Force tracing to be dependent on our mock variable here.
     gpu_trace_srv_category = &tracing_enabled_;
     gpu_trace_dev_category = &tracing_enabled_;
@@ -182,10 +169,6 @@
     set_outputter_ = outputter;
   }
 
-  void SetCPUTime(scoped_refptr<CPUTime> cputime) {
-    set_cputime_ = cputime;
-  }
-
  protected:
   scoped_refptr<Outputter> CreateOutputter(const std::string& name) override {
     if (set_outputter_.get()) {
@@ -194,72 +177,52 @@
     return new MockOutputter();
   }
 
-  scoped_refptr<CPUTime> CreateCPUTime() override {
-    if (set_cputime_.get()) {
-      return set_cputime_;
-    }
-    return new FakeCPUTime();
-  }
-
-  GpuTracerType DetermineTracerType() override {
-    return test_tracer_type_;
-  }
-
   void PostTask() override {
     // Process synchronously.
     Process();
   }
 
   unsigned char tracing_enabled_;
-  GpuTracerType test_tracer_type_;
 
   scoped_refptr<Outputter> set_outputter_;
-  scoped_refptr<CPUTime> set_cputime_;
 };
 
 class BaseGpuTest : public GpuServiceTest {
  public:
-  BaseGpuTest(GpuTracerType test_tracer_type)
-      : test_tracer_type_(test_tracer_type) {
+  explicit BaseGpuTest(GPUTiming::TimerType test_timer_type)
+      : test_timer_type_(test_timer_type) {
+    gpu_timing_.SetCpuTimeForTesting(base::Bind(&FakeCpuTime));
+    gpu_timing_.SetTimerTypeForTesting(test_timer_type);
   }
 
  protected:
   void SetUp() override {
+    g_fakeCPUTime = 0;
     const char* gl_version = "3.2";
-    const char* extensions = nullptr;
-    if (GetTracerType() == kTracerTypeDisjointTimer) {
+    const char* extensions = "";
+    if (GetTimerType() == GPUTiming::kTimerTypeDisjoint) {
       gl_version = "opengl es 3.0";
       extensions = "GL_EXT_disjoint_timer_query";
-    } else if (GetTracerType() == kTracerTypeARBTimer) {
+    } else if (GetTimerType() == GPUTiming::kTimerTypeARB) {
       // TODO(sievers): The tracer should not depend on ARB_occlusion_query.
       // Try merge Query APIs (core, ARB, EXT) into a single binding each.
       extensions = "GL_ARB_timer_query GL_ARB_occlusion_query";
     }
     GpuServiceTest::SetUpWithGLVersion(gl_version, extensions);
     gl_fake_queries_.Reset();
-    gl_surface_ = new gfx::GLSurfaceStub();
-    gl_context_ = new gfx::GLContextStub();
-    gl_context_->MakeCurrent(gl_surface_.get());
 
     outputter_ref_ = new MockOutputter();
-    cpu_time_ref_ = new FakeCPUTime;
   }
 
   void TearDown() override {
     outputter_ref_ = NULL;
-    cpu_time_ref_ = NULL;
 
-    gl_context_->ReleaseCurrent(gl_surface_.get());
-    gl_context_ = NULL;
-    gl_surface_ = NULL;
-
-    gl_.reset();
     gl_fake_queries_.Reset();
     GpuServiceTest::TearDown();
   }
 
   void ExpectTraceQueryMocks() {
-    if (GetTracerType() != kTracerTypeInvalid) {
+    if (GetTimerType() != GPUTiming::kTimerTypeInvalid) {
       // Delegate query APIs used by GPUTrace to a GlFakeQueries
       EXPECT_CALL(*gl_, GenQueriesARB(2, NotNull())).Times(AtLeast(1))
           .WillRepeatedly(
@@ -270,7 +233,7 @@
           .WillRepeatedly(
                Invoke(&gl_fake_queries_, &GlFakeQueries::GetQueryObjectivARB));
 
-      if (GetTracerType() == kTracerTypeDisjointTimer) {
+      if (GetTimerType() == GPUTiming::kTimerTypeDisjoint) {
         EXPECT_CALL(*gl_, GetInteger64v(GL_TIMESTAMP, _))
           .WillRepeatedly(
                Invoke(&gl_fake_queries_, &GlFakeQueries::GetInteger64v));
@@ -323,14 +286,14 @@
                             const std::string& name, int64 expect_start_time,
                             int64 expect_end_time) {
     ExpectOutputterBeginMocks(outputter, category, name);
-    ExpectOutputterEndMocks(outputter, category, name,
-                            expect_start_time, expect_end_time,
-                            GetTracerType() != kTracerTypeInvalid);
+    ExpectOutputterEndMocks(outputter, category, name, expect_start_time,
+                            expect_end_time,
+                            GetTimerType() != GPUTiming::kTimerTypeInvalid);
   }
 
   void ExpectTracerOffsetQueryMocks() {
     // Disjoint check should only be called by kTracerTypeDisjointTimer type.
-    if (GetTracerType() == kTracerTypeDisjointTimer) {
+    if (GetTimerType() == GPUTiming::kTimerTypeDisjoint) {
       EXPECT_CALL(*gl_, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(AtLeast(1))
           .WillRepeatedly(
               Invoke(&gl_fake_queries_, &GlFakeQueries::GetIntegerv));
@@ -338,36 +301,31 @@
       EXPECT_CALL(*gl_, GetIntegerv(GL_GPU_DISJOINT_EXT, _)).Times(Exactly(0));
     }
 
-    // Timer offset calculation should only happen for the regular timer.
-    if (GetTracerType() != kTracerTypeARBTimer) {
+    if (GetTimerType() != GPUTiming::kTimerTypeARB) {
       EXPECT_CALL(*gl_, GetInteger64v(GL_TIMESTAMP, NotNull()))
           .Times(Exactly(0));
     } else {
       EXPECT_CALL(*gl_, GetInteger64v(GL_TIMESTAMP, NotNull()))
-          .Times(AtLeast(1))
+          .Times(AtMost(1))
           .WillRepeatedly(
               Invoke(&gl_fake_queries_, &GlFakeQueries::GetInteger64v));
     }
   }
 
-  GpuTracerType GetTracerType() { return test_tracer_type_; }
+  GPUTiming::TimerType GetTimerType() { return test_timer_type_; }
 
-  GpuTracerType test_tracer_type_;
+  GPUTiming::TimerType test_timer_type_;
   GlFakeQueries gl_fake_queries_;
 
+  GPUTiming gpu_timing_;
   scoped_refptr<MockOutputter> outputter_ref_;
-  scoped_refptr<FakeCPUTime> cpu_time_ref_;
-
-  scoped_refptr<gfx::GLSurface> gl_surface_;
-  scoped_refptr<gfx::GLContext> gl_context_;
 };
 
 // Test GPUTrace calls all the correct gl calls.
 class BaseGpuTraceTest : public BaseGpuTest {
  public:
-  BaseGpuTraceTest(GpuTracerType test_tracer_type)
-      : BaseGpuTest(test_tracer_type) {
-  }
+  explicit BaseGpuTraceTest(GPUTiming::TimerType test_timer_type)
+      : BaseGpuTest(test_timer_type) {}
 
   void DoTraceTest() {
     // Expected results
@@ -386,12 +344,14 @@
     ExpectOutputterMocks(outputter_ref_.get(), category_name, trace_name,
                          expect_start_time, expect_end_time);
 
-    scoped_refptr<GPUTrace> trace =
-        new GPUTrace(outputter_ref_, cpu_time_ref_, category_name, trace_name,
-                     offset_time, GetTracerType());
+    scoped_refptr<GPUTrace> trace = new GPUTrace(
+        outputter_ref_, &gpu_timing_, category_name, trace_name, true);
+
+    gpu_timing_.SetOffsetForTesting(
+        offset_time, test_timer_type_ == GPUTiming::kTimerTypeARB);
 
     gl_fake_queries_.SetCurrentGLTime(start_timestamp);
-    cpu_time_ref_->SetFakeCPUTime(expect_start_time);
+    g_fakeCPUTime = expect_start_time;
     trace->Start(true);
 
     // Shouldn't be available before End() call
@@ -413,22 +373,18 @@
     trace->Process();
 
     outputter_ref_ = NULL;
-    cpu_time_ref_ = NULL;
   }
 };
 
 class GpuARBTimerTraceTest : public BaseGpuTraceTest {
  public:
-  GpuARBTimerTraceTest()
-      : BaseGpuTraceTest(kTracerTypeARBTimer) {
-  }
+  GpuARBTimerTraceTest() : BaseGpuTraceTest(GPUTiming::kTimerTypeARB) {}
 };
 
 class GpuDisjointTimerTraceTest : public BaseGpuTraceTest {
  public:
   GpuDisjointTimerTraceTest()
-      : BaseGpuTraceTest(kTracerTypeDisjointTimer) {
-  }
+      : BaseGpuTraceTest(GPUTiming::kTimerTypeDisjoint) {}
 };
 
 TEST_F(GpuARBTimerTraceTest, ARBTimerTraceTest) {
@@ -442,25 +398,23 @@
 // Test GPUTracer calls all the correct gl calls.
 class BaseGpuTracerTest : public BaseGpuTest {
  public:
-  BaseGpuTracerTest(GpuTracerType test_tracer_type)
-      : BaseGpuTest(test_tracer_type) {
-  }
+  explicit BaseGpuTracerTest(GPUTiming::TimerType test_timer_type)
+      : BaseGpuTest(test_timer_type) {}
 
   void DoBasicTracerTest() {
     ExpectTracerOffsetQueryMocks();
 
     MockGLES2Decoder decoder;
-    GPUTracerTester tracer(test_tracer_type_, &decoder);
+    EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
+    GPUTracerTester tracer(&decoder);
     tracer.SetTracingEnabled(true);
 
     tracer.SetOutputter(outputter_ref_);
-    tracer.SetCPUTime(cpu_time_ref_);
 
     ASSERT_TRUE(tracer.BeginDecoding());
     ASSERT_TRUE(tracer.EndDecoding());
 
     outputter_ref_ = NULL;
-    cpu_time_ref_ = NULL;
   }
 
   void DoTracerMarkersTest() {
@@ -482,14 +436,14 @@
         (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time;
 
     MockGLES2Decoder decoder;
-    GPUTracerTester tracer(test_tracer_type_, &decoder);
+    EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
+    GPUTracerTester tracer(&decoder);
     tracer.SetTracingEnabled(true);
 
     tracer.SetOutputter(outputter_ref_);
-    tracer.SetCPUTime(cpu_time_ref_);
 
     gl_fake_queries_.SetCurrentGLTime(start_timestamp);
-    cpu_time_ref_->SetFakeCPUTime(expect_start_time);
+    g_fakeCPUTime = expect_start_time;
 
     ASSERT_TRUE(tracer.BeginDecoding());
 
@@ -501,7 +455,7 @@
       gl_fake_queries_.SetCurrentGLTime(
           start_timestamp +
           (i * base::Time::kNanosecondsPerMicrosecond));
-      cpu_time_ref_->SetFakeCPUTime(expect_start_time + i);
+      g_fakeCPUTime = expect_start_time + i;
 
       // Each trace name should be different to differentiate.
       const char num_char = static_cast<char>('0' + i);
@@ -520,7 +474,7 @@
       gl_fake_queries_.SetCurrentGLTime(
           end_timestamp +
           (i * base::Time::kNanosecondsPerMicrosecond));
-      cpu_time_ref_->SetFakeCPUTime(expect_end_time + i);
+      g_fakeCPUTime = expect_start_time + i;
 
       // Each trace name should be different to differentiate.
       const char num_char = static_cast<char>('0' + i);
@@ -528,9 +482,9 @@
       std::string source_trace_name = trace_name + num_char;
 
       ExpectOutputterEndMocks(outputter_ref_.get(), source_category,
-                              source_trace_name,
-                              expect_start_time + i, expect_end_time + i,
-                              GetTracerType() != kTracerTypeInvalid);
+                              source_trace_name, expect_start_time + i,
+                              expect_end_time + i,
+                              GetTimerType() != GPUTiming::kTimerTypeInvalid);
 
       const GpuTracerSource source = static_cast<GpuTracerSource>(i);
 
@@ -544,7 +498,6 @@
     ASSERT_TRUE(tracer.EndDecoding());
 
     outputter_ref_ = NULL;
-    cpu_time_ref_ = NULL;
   }
 
   void DoDisjointTest() {
@@ -568,14 +521,14 @@
         (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time;
 
     MockGLES2Decoder decoder;
-    GPUTracerTester tracer(test_tracer_type_, &decoder);
+    EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
+    GPUTracerTester tracer(&decoder);
     tracer.SetTracingEnabled(true);
 
     tracer.SetOutputter(outputter_ref_);
-    tracer.SetCPUTime(cpu_time_ref_);
 
     gl_fake_queries_.SetCurrentGLTime(start_timestamp);
-    cpu_time_ref_->SetFakeCPUTime(expect_start_time);
+    g_fakeCPUTime = expect_start_time;
 
     ASSERT_TRUE(tracer.BeginDecoding());
 
@@ -586,7 +539,7 @@
     ASSERT_TRUE(tracer.Begin(category_name, trace_name, source));
 
     gl_fake_queries_.SetCurrentGLTime(end_timestamp);
-    cpu_time_ref_->SetFakeCPUTime(expect_end_time);
+    g_fakeCPUTime = expect_end_time;
     gl_fake_queries_.SetDisjoint();
 
     ExpectOutputterEndMocks(outputter_ref_.get(), category_name, trace_name,
@@ -596,29 +549,23 @@
     ASSERT_TRUE(tracer.EndDecoding());
 
     outputter_ref_ = NULL;
-    cpu_time_ref_ = NULL;
   }
 };
 
 class InvalidTimerTracerTest : public BaseGpuTracerTest {
  public:
-  InvalidTimerTracerTest()
-      : BaseGpuTracerTest(kTracerTypeInvalid) {
-  }
+  InvalidTimerTracerTest() : BaseGpuTracerTest(GPUTiming::kTimerTypeInvalid) {}
 };
 
 class GpuARBTimerTracerTest : public BaseGpuTracerTest {
  public:
-  GpuARBTimerTracerTest()
-      : BaseGpuTracerTest(kTracerTypeARBTimer) {
-  }
+  GpuARBTimerTracerTest() : BaseGpuTracerTest(GPUTiming::kTimerTypeARB) {}
 };
 
 class GpuDisjointTimerTracerTest : public BaseGpuTracerTest {
  public:
   GpuDisjointTimerTracerTest()
-      : BaseGpuTracerTest(kTracerTypeDisjointTimer) {
-  }
+      : BaseGpuTracerTest(GPUTiming::kTimerTypeDisjoint) {}
 };
 
 TEST_F(InvalidTimerTracerTest, InvalidTimerBasicTracerTest) {
@@ -649,38 +596,53 @@
   DoDisjointTest();
 }
 
+class GPUTracerTest : public GpuServiceTest {
+ protected:
+  void SetUp() override {
+    g_fakeCPUTime = 0;
+    GpuServiceTest::SetUpWithGLVersion("3.2", "");
+    decoder_.reset(new MockGLES2Decoder());
+    EXPECT_CALL(*decoder_, GetGLContext())
+        .Times(AtMost(1))
+        .WillRepeatedly(Return(GetGLContext()));
+    tracer_tester_.reset(new GPUTracerTester(decoder_.get()));
+  }
+
+  void TearDown() override {
+    tracer_tester_ = nullptr;
+    decoder_ = nullptr;
+    GpuServiceTest::TearDown();
+  }
+  scoped_ptr<MockGLES2Decoder> decoder_;
+  scoped_ptr<GPUTracerTester> tracer_tester_;
+};
+
+TEST_F(GPUTracerTest, IsTracingTest) {
+  EXPECT_FALSE(tracer_tester_->IsTracing());
+  tracer_tester_->SetTracingEnabled(true);
+  EXPECT_TRUE(tracer_tester_->IsTracing());
+}
 // Test basic functionality of the GPUTracerTester.
-TEST(GPUTracerTester, IsTracingTest) {
-  MockGLES2Decoder decoder;
-  GPUTracerTester tracer_tester(kTracerTypeInvalid, &decoder);
-  EXPECT_FALSE(tracer_tester.IsTracing());
-  tracer_tester.SetTracingEnabled(true);
-  EXPECT_TRUE(tracer_tester.IsTracing());
+TEST_F(GPUTracerTest, DecodeTest) {
+  ASSERT_TRUE(tracer_tester_->BeginDecoding());
+  EXPECT_FALSE(tracer_tester_->BeginDecoding());
+  ASSERT_TRUE(tracer_tester_->EndDecoding());
+  EXPECT_FALSE(tracer_tester_->EndDecoding());
 }
 
-TEST(GPUTracerTester, DecodeTest) {
-  MockGLES2Decoder decoder;
-  GPUTracerTester tracer_tester(kTracerTypeInvalid, &decoder);
-  ASSERT_TRUE(tracer_tester.BeginDecoding());
-  EXPECT_FALSE(tracer_tester.BeginDecoding());
-  ASSERT_TRUE(tracer_tester.EndDecoding());
-  EXPECT_FALSE(tracer_tester.EndDecoding());
-}
-
-TEST(GPUTracerTester, TraceDuringDecodeTest) {
-  MockGLES2Decoder decoder;
-  GPUTracerTester tracer_tester(kTracerTypeInvalid, &decoder);
+TEST_F(GPUTracerTest, TraceDuringDecodeTest) {
   const std::string category_name("trace_category");
   const std::string trace_name("trace_test");
 
-  EXPECT_FALSE(tracer_tester.Begin(category_name, trace_name,
-                                   kTraceGroupMarker));
+  EXPECT_FALSE(
+      tracer_tester_->Begin(category_name, trace_name, kTraceGroupMarker));
 
-  ASSERT_TRUE(tracer_tester.BeginDecoding());
-  EXPECT_TRUE(tracer_tester.Begin(category_name, trace_name,
-                                  kTraceGroupMarker));
-  ASSERT_TRUE(tracer_tester.EndDecoding());
+  ASSERT_TRUE(tracer_tester_->BeginDecoding());
+  EXPECT_TRUE(
+      tracer_tester_->Begin(category_name, trace_name, kTraceGroupMarker));
+  ASSERT_TRUE(tracer_tester_->EndDecoding());
 }
 
+}  // namespace
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 5db80b0..c4fa167 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -31,6 +31,7 @@
 #include "gpu/command_buffer/service/mailbox_manager_sync.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/command_buffer/service/query_manager.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
 #include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "ui/gfx/geometry/size.h"
@@ -130,60 +131,64 @@
   base::WaitableEvent* event_;
 };
 
-class SyncPointManager {
+// This wrapper adds the WaitSyncPoint which allows waiting on a sync point
+// on the service thread, implemented using a condition variable.
+class SyncPointManagerWrapper {
  public:
-  SyncPointManager();
-  ~SyncPointManager();
+  SyncPointManagerWrapper();
 
   uint32 GenerateSyncPoint();
   void RetireSyncPoint(uint32 sync_point);
+  void AddSyncPointCallback(uint32 sync_point, const base::Closure& callback);
 
-  bool IsSyncPointPassed(uint32 sync_point);
   void WaitSyncPoint(uint32 sync_point);
 
-private:
-  // This lock protects access to pending_sync_points_ and next_sync_point_ and
-  // is used with the ConditionVariable to signal when a sync point is retired.
-  base::Lock lock_;
-  std::set<uint32> pending_sync_points_;
-  uint32 next_sync_point_;
-  base::ConditionVariable cond_var_;
+ private:
+  void OnSyncPointRetired();
+
+  const scoped_refptr<SyncPointManager> manager_;
+  base::Lock retire_lock_;
+  base::ConditionVariable retire_cond_var_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyncPointManagerWrapper);
 };
 
-SyncPointManager::SyncPointManager() : next_sync_point_(1), cond_var_(&lock_) {}
-
-SyncPointManager::~SyncPointManager() {
-  DCHECK_EQ(pending_sync_points_.size(), 0U);
+SyncPointManagerWrapper::SyncPointManagerWrapper()
+    : manager_(SyncPointManager::Create(true)),
+      retire_cond_var_(&retire_lock_) {
 }
 
-uint32 SyncPointManager::GenerateSyncPoint() {
-  base::AutoLock lock(lock_);
-  uint32 sync_point = next_sync_point_++;
-  DCHECK_EQ(pending_sync_points_.count(sync_point), 0U);
-  pending_sync_points_.insert(sync_point);
+uint32 SyncPointManagerWrapper::GenerateSyncPoint() {
+  uint32 sync_point = manager_->GenerateSyncPoint();
+  manager_->AddSyncPointCallback(
+      sync_point, base::Bind(&SyncPointManagerWrapper::OnSyncPointRetired,
+                             base::Unretained(this)));
   return sync_point;
 }
 
-void SyncPointManager::RetireSyncPoint(uint32 sync_point) {
-  base::AutoLock lock(lock_);
-  DCHECK(pending_sync_points_.count(sync_point));
-  pending_sync_points_.erase(sync_point);
-  cond_var_.Broadcast();
+void SyncPointManagerWrapper::RetireSyncPoint(uint32 sync_point) {
+  manager_->RetireSyncPoint(sync_point);
 }
 
-bool SyncPointManager::IsSyncPointPassed(uint32 sync_point) {
-  base::AutoLock lock(lock_);
-  return pending_sync_points_.count(sync_point) == 0;
+void SyncPointManagerWrapper::AddSyncPointCallback(
+    uint32 sync_point,
+    const base::Closure& callback) {
+  manager_->AddSyncPointCallback(sync_point, callback);
 }
 
-void SyncPointManager::WaitSyncPoint(uint32 sync_point) {
-  base::AutoLock lock(lock_);
-  while (pending_sync_points_.count(sync_point)) {
-    cond_var_.Wait();
+void SyncPointManagerWrapper::WaitSyncPoint(uint32 sync_point) {
+  base::AutoLock lock(retire_lock_);
+  while (!manager_->IsSyncPointRetired(sync_point)) {
+    retire_cond_var_.Wait();
   }
 }
 
-base::LazyInstance<SyncPointManager> g_sync_point_manager =
+void SyncPointManagerWrapper::OnSyncPointRetired() {
+  base::AutoLock lock(retire_lock_);
+  retire_cond_var_.Broadcast();
+}
+
+base::LazyInstance<SyncPointManagerWrapper> g_sync_point_manager =
     LAZY_INSTANCE_INITIALIZER;
 
 base::SharedMemoryHandle ShareToGpuThread(
@@ -858,15 +863,7 @@
 void InProcessCommandBuffer::SignalSyncPointOnGpuThread(
     unsigned sync_point,
     const base::Closure& callback) {
-  if (g_sync_point_manager.Get().IsSyncPointPassed(sync_point)) {
-    callback.Run();
-  } else {
-    service_->ScheduleIdleWork(
-        base::Bind(&InProcessCommandBuffer::SignalSyncPointOnGpuThread,
-                   gpu_thread_weak_ptr_,
-                   sync_point,
-                   callback));
-  }
+  g_sync_point_manager.Get().AddSyncPointCallback(sync_point, callback);
 }
 
 void InProcessCommandBuffer::SignalQuery(unsigned query_id,
@@ -906,6 +903,9 @@
   return stream_id;
 }
 
+void InProcessCommandBuffer::SetLock(base::Lock*) {
+}
+
 uint32 InProcessCommandBuffer::CreateStreamTextureOnGpuThread(
     uint32 client_texture_id) {
 #if defined(OS_ANDROID)
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index 3be3602..b3f6eb8 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -120,6 +120,7 @@
   void SignalQuery(uint32 query_id, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
+  void SetLock(base::Lock*) override;
 
   // The serializer interface to the GPU service (i.e. thread).
   class Service {
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index 1e8e11b..16509e5 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -15,7 +15,6 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "gpu/command_buffer/service/shader_manager.h"
-#include "gpu/command_buffer/service/shader_translator.h"
 #include "ui/gl/gl_bindings.h"
 
 namespace {
@@ -173,9 +172,7 @@
 ProgramCache::ProgramLoadResult MemoryProgramCache::LoadLinkedProgram(
     GLuint program,
     Shader* shader_a,
-    const ShaderTranslatorInterface* translator_a,
     Shader* shader_b,
-    const ShaderTranslatorInterface* translator_b,
     const LocationMap* bind_attrib_location_map,
     const ShaderCacheCallback& shader_callback) {
   char a_sha[kHashLength];
@@ -183,9 +180,9 @@
   DCHECK(shader_a && !shader_a->last_compiled_source().empty() &&
          shader_b && !shader_b->last_compiled_source().empty());
   ComputeShaderHash(
-      shader_a->last_compiled_source(), translator_a, a_sha);
+      shader_a->last_compiled_signature(), a_sha);
   ComputeShaderHash(
-      shader_b->last_compiled_source(), translator_b, b_sha);
+      shader_b->last_compiled_signature(), b_sha);
 
   char sha[kHashLength];
   ComputeProgramHash(a_sha,
@@ -235,9 +232,7 @@
 void MemoryProgramCache::SaveLinkedProgram(
     GLuint program,
     const Shader* shader_a,
-    const ShaderTranslatorInterface* translator_a,
     const Shader* shader_b,
-    const ShaderTranslatorInterface* translator_b,
     const LocationMap* bind_attrib_location_map,
     const ShaderCacheCallback& shader_callback) {
   GLenum format;
@@ -259,9 +254,9 @@
   DCHECK(shader_a && !shader_a->last_compiled_source().empty() &&
          shader_b && !shader_b->last_compiled_source().empty());
   ComputeShaderHash(
-      shader_a->last_compiled_source(), translator_a, a_sha);
+      shader_a->last_compiled_signature(), a_sha);
   ComputeShaderHash(
-      shader_b->last_compiled_source(), translator_b, b_sha);
+      shader_b->last_compiled_signature(), b_sha);
 
   char sha[kHashLength];
   ComputeProgramHash(a_sha,
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h
index 7560d01..b5862d2 100644
--- a/gpu/command_buffer/service/memory_program_cache.h
+++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -14,7 +14,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/program_cache.h"
-#include "gpu/command_buffer/service/shader_translator.h"
 
 namespace gpu {
 namespace gles2 {
@@ -29,16 +28,12 @@
   ProgramLoadResult LoadLinkedProgram(
       GLuint program,
       Shader* shader_a,
-      const ShaderTranslatorInterface* translator_a,
       Shader* shader_b,
-      const ShaderTranslatorInterface* translator_b,
       const LocationMap* bind_attrib_location_map,
       const ShaderCacheCallback& shader_callback) override;
   void SaveLinkedProgram(GLuint program,
                          const Shader* shader_a,
-                         const ShaderTranslatorInterface* translator_a,
                          const Shader* shader_b,
-                         const ShaderTranslatorInterface* translator_b,
                          const LocationMap* bind_attrib_location_map,
                          const ShaderCacheCallback& shader_callback) override;
 
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index 8f8c430..795b0af 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -190,16 +190,14 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      vertex_shader_->last_compiled_source(),
-      NULL,
-      fragment_shader_->last_compiled_source(),
-      NULL,
+      vertex_shader_->last_compiled_signature(),
+      fragment_shader_->last_compiled_signature(),
       NULL));
   EXPECT_EQ(1, shader_cache_count());
 }
@@ -215,16 +213,14 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      vertex_shader_->last_compiled_source(),
-      NULL,
-      fragment_shader_->last_compiled_source(),
-      NULL,
+      vertex_shader_->last_compiled_signature(),
+      fragment_shader_->last_compiled_signature(),
       NULL));
   EXPECT_EQ(1, shader_cache_count());
 
@@ -232,10 +228,8 @@
 
   cache_->LoadProgram(shader_cache_shader());
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      vertex_shader_->last_compiled_source(),
-      NULL,
-      fragment_shader_->last_compiled_source(),
-      NULL,
+      vertex_shader_->last_compiled_signature(),
+      fragment_shader_->last_compiled_signature(),
       NULL));
 }
 
@@ -250,8 +244,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
   EXPECT_EQ(1, shader_cache_count());
@@ -275,10 +269,8 @@
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
       NULL,
-      NULL,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
 
@@ -305,8 +297,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
   EXPECT_EQ(1, shader_cache_count());
@@ -333,10 +325,8 @@
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
       NULL,
-      NULL,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
 
@@ -363,8 +353,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
@@ -372,10 +362,8 @@
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
       NULL,
-      NULL,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
 }
@@ -391,8 +379,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
@@ -402,10 +390,8 @@
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
       NULL,
-      NULL,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
 
@@ -416,10 +402,8 @@
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
       NULL,
-      NULL,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
 }
@@ -439,9 +423,7 @@
   binding_map["test"] = 512;
   cache_->SaveLinkedProgram(kProgramId,
                             vertex_shader_,
-                            NULL,
                             fragment_shader_,
-                            NULL,
                             &binding_map,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
@@ -450,19 +432,15 @@
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
-      NULL,
       &binding_map,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
       NULL,
-      NULL,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
 }
@@ -479,8 +457,8 @@
 
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
@@ -488,7 +466,7 @@
   const GLuint kEvictingBinaryLength = kCacheSizeBytes - kBinaryLength + 1;
 
   // save old source and modify for new program
-  const std::string& old_source = fragment_shader_->last_compiled_source();
+  const std::string& old_sig = fragment_shader_->last_compiled_signature();
   fragment_shader_->set_source("al sdfkjdk");
   TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true);
 
@@ -504,24 +482,18 @@
   SetExpectationsForSaveLinkedProgram(kEvictingProgramId, &emulator2);
   cache_->SaveLinkedProgram(kEvictingProgramId,
                             vertex_shader_,
-                            NULL,
                             fragment_shader_,
                             NULL,
-                            NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      vertex_shader_->last_compiled_source(),
-      NULL,
-      fragment_shader_->last_compiled_source(),
-      NULL,
+      vertex_shader_->last_compiled_signature(),
+      fragment_shader_->last_compiled_signature(),
       NULL));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(
-      old_source,
-      NULL,
-      fragment_shader_->last_compiled_source(),
-      NULL,
+      old_sig,
+      fragment_shader_->last_compiled_signature(),
       NULL));
 }
 
@@ -537,16 +509,14 @@
 
   vertex_shader_->set_source("different!");
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      vertex_shader_->last_compiled_source(),
-      NULL,
-      fragment_shader_->last_compiled_source(),
-      NULL,
+      vertex_shader_->last_compiled_signature(),
+      fragment_shader_->last_compiled_signature(),
       NULL));
 }
 
@@ -561,16 +531,14 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      vertex_shader_->last_compiled_source(),
-      NULL,
-      fragment_shader_->last_compiled_source(),
-      NULL,
+      vertex_shader_->last_compiled_signature(),
+      fragment_shader_->last_compiled_signature(),
       NULL));
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
@@ -579,10 +547,8 @@
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
       NULL,
-      NULL,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
 }
@@ -598,8 +564,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
@@ -610,8 +576,8 @@
   }
   ProgramBinaryEmulator emulator2(kBinaryLength, kFormat, test_binary2);
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator2);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
-                            fragment_shader_, NULL, NULL,
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
+                            fragment_shader_, NULL,
                             base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                                        base::Unretained(this)));
 
@@ -619,10 +585,8 @@
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
-      NULL,
       fragment_shader_,
       NULL,
-      NULL,
       base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
                  base::Unretained(this))));
 }
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h
index 87b3136..d5cff51 100644
--- a/gpu/command_buffer/service/mocks.h
+++ b/gpu/command_buffer/service/mocks.h
@@ -88,7 +88,6 @@
 class MockShaderTranslator : public ShaderTranslatorInterface {
  public:
   MockShaderTranslator();
-  virtual ~MockShaderTranslator();
 
   MOCK_METHOD5(Init, bool(
       sh::GLenum shader_type,
@@ -106,6 +105,8 @@
       NameMap* name_map));
   MOCK_CONST_METHOD0(
       GetStringForOptionsThatWouldAffectCompilation, std::string());
+ private:
+  ~MockShaderTranslator() override;
 };
 
 class MockProgramCache : public ProgramCache {
@@ -113,21 +114,17 @@
   MockProgramCache();
   virtual ~MockProgramCache();
 
-  MOCK_METHOD7(LoadLinkedProgram, ProgramLoadResult(
+  MOCK_METHOD5(LoadLinkedProgram, ProgramLoadResult(
       GLuint program,
       Shader* shader_a,
-      const ShaderTranslatorInterface* translator_a,
       Shader* shader_b,
-      const ShaderTranslatorInterface* translator_b,
       const LocationMap* bind_attrib_location_map,
       const ShaderCacheCallback& callback));
 
-  MOCK_METHOD7(SaveLinkedProgram, void(
+  MOCK_METHOD5(SaveLinkedProgram, void(
       GLuint program,
       const Shader* shader_a,
-      const ShaderTranslatorInterface* translator_a,
       const Shader* shader_b,
-      const ShaderTranslatorInterface* translator_b,
       const LocationMap* bind_attrib_location_map,
       const ShaderCacheCallback& callback));
   MOCK_METHOD1(LoadProgram, void(const std::string&));
diff --git a/gpu/command_buffer/service/program_cache.cc b/gpu/command_buffer/service/program_cache.cc
index abdcfc0..b219086 100644
--- a/gpu/command_buffer/service/program_cache.cc
+++ b/gpu/command_buffer/service/program_cache.cc
@@ -20,15 +20,13 @@
 }
 
 ProgramCache::LinkedProgramStatus ProgramCache::GetLinkedProgramStatus(
-    const std::string& untranslated_a,
-    const ShaderTranslatorInterface* translator_a,
-    const std::string& untranslated_b,
-    const ShaderTranslatorInterface* translator_b,
+    const std::string& shader_signature_a,
+    const std::string& shader_signature_b,
     const std::map<std::string, GLint>* bind_attrib_location_map) const {
   char a_sha[kHashLength];
   char b_sha[kHashLength];
-  ComputeShaderHash(untranslated_a, translator_a, a_sha);
-  ComputeShaderHash(untranslated_b, translator_b, b_sha);
+  ComputeShaderHash(shader_signature_a, a_sha);
+  ComputeShaderHash(shader_signature_b, b_sha);
 
   char sha[kHashLength];
   ComputeProgramHash(a_sha,
@@ -46,15 +44,13 @@
 }
 
 void ProgramCache::LinkedProgramCacheSuccess(
-    const std::string& shader_a,
-    const ShaderTranslatorInterface* translator_a,
-    const std::string& shader_b,
-    const ShaderTranslatorInterface* translator_b,
+    const std::string& shader_signature_a,
+    const std::string& shader_signature_b,
     const LocationMap* bind_attrib_location_map) {
   char a_sha[kHashLength];
   char b_sha[kHashLength];
-  ComputeShaderHash(shader_a, translator_a, a_sha);
-  ComputeShaderHash(shader_b, translator_b, b_sha);
+  ComputeShaderHash(shader_signature_a, a_sha);
+  ComputeShaderHash(shader_signature_b, b_sha);
   char sha[kHashLength];
   ComputeProgramHash(a_sha,
                      b_sha,
@@ -71,13 +67,9 @@
 
 void ProgramCache::ComputeShaderHash(
     const std::string& str,
-    const ShaderTranslatorInterface* translator,
     char* result) const {
-  std::string s((
-      translator ? translator->GetStringForOptionsThatWouldAffectCompilation() :
-                   std::string()) + str);
-  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(s.c_str()),
-                      s.length(), reinterpret_cast<unsigned char*>(result));
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.c_str()),
+                      str.length(), reinterpret_cast<unsigned char*>(result));
 }
 
 void ProgramCache::Evict(const std::string& program_hash) {
diff --git a/gpu/command_buffer/service/program_cache.h b/gpu/command_buffer/service/program_cache.h
index 3fb5687..624c436 100644
--- a/gpu/command_buffer/service/program_cache.h
+++ b/gpu/command_buffer/service/program_cache.h
@@ -18,7 +18,6 @@
 namespace gles2 {
 
 class Shader;
-class ShaderTranslator;
 
 // Program cache base class for caching linked gpu programs
 class GPU_EXPORT ProgramCache {
@@ -41,10 +40,8 @@
   virtual ~ProgramCache();
 
   LinkedProgramStatus GetLinkedProgramStatus(
-      const std::string& untranslated_shader_a,
-      const ShaderTranslatorInterface* translator_a,
-      const std::string& untranslated_shader_b,
-      const ShaderTranslatorInterface* translator_b,
+      const std::string& shader_signature_a,
+      const std::string& shader_signature_b,
       const LocationMap* bind_attrib_location_map) const;
 
   // Loads the linked program from the cache.  If the program is not found or
@@ -52,9 +49,7 @@
   virtual ProgramLoadResult LoadLinkedProgram(
       GLuint program,
       Shader* shader_a,
-      const ShaderTranslatorInterface* translator_a,
       Shader* shader_b,
-      const ShaderTranslatorInterface* translator_b,
       const LocationMap* bind_attrib_location_map,
       const ShaderCacheCallback& shader_callback) = 0;
 
@@ -63,9 +58,7 @@
   virtual void SaveLinkedProgram(
       GLuint program,
       const Shader* shader_a,
-      const ShaderTranslatorInterface* translator_a,
       const Shader* shader_b,
-      const ShaderTranslatorInterface* translator_b,
       const LocationMap* bind_attrib_location_map,
       const ShaderCacheCallback& shader_callback) = 0;
 
@@ -75,10 +68,8 @@
   void Clear();
 
   // Only for testing
-  void LinkedProgramCacheSuccess(const std::string& shader_a,
-                                 const ShaderTranslatorInterface* translator_a,
-                                 const std::string& shader_b,
-                                 const ShaderTranslatorInterface* translator_b,
+  void LinkedProgramCacheSuccess(const std::string& shader_signature_a,
+                                 const std::string& shader_signature_b,
                                  const LocationMap* bind_attrib_location_map);
 
  protected:
@@ -87,7 +78,6 @@
 
   // result is not null terminated
   void ComputeShaderHash(const std::string& shader,
-                         const ShaderTranslatorInterface* translator,
                          char* result) const;
 
   // result is not null terminated.  hashed shaders are expected to be
diff --git a/gpu/command_buffer/service/program_cache_unittest.cc b/gpu/command_buffer/service/program_cache_unittest.cc
index 525fea1..7a4cbcd 100644
--- a/gpu/command_buffer/service/program_cache_unittest.cc
+++ b/gpu/command_buffer/service/program_cache_unittest.cc
@@ -18,18 +18,14 @@
   ProgramLoadResult LoadLinkedProgram(
       GLuint /* program */,
       Shader* /* shader_a */,
-      const ShaderTranslatorInterface* /* translator_a */,
       Shader* /* shader_b */,
-      const ShaderTranslatorInterface* /* translator_b */,
       const LocationMap* /* bind_attrib_location_map */,
       const ShaderCacheCallback& /* callback */) override {
     return PROGRAM_LOAD_SUCCESS;
   }
   void SaveLinkedProgram(GLuint /* program */,
                          const Shader* /* shader_a */,
-                         const ShaderTranslatorInterface* /* translator_b */,
                          const Shader* /* shader_b */,
-                         const ShaderTranslatorInterface* /* translator_b */,
                          const LocationMap* /* bind_attrib_location_map */,
                          const ShaderCacheCallback& /* callback */) override {}
 
@@ -38,14 +34,12 @@
   void ClearBackend() override {}
 
   void SaySuccessfullyCached(const std::string& shader1,
-                             const ShaderTranslatorInterface* translator_1,
                              const std::string& shader2,
-                             const ShaderTranslatorInterface* translator_2,
                              std::map<std::string, GLint>* attrib_map) {
     char a_sha[kHashLength];
     char b_sha[kHashLength];
-    ComputeShaderHash(shader1, translator_1, a_sha);
-    ComputeShaderHash(shader2, translator_2, b_sha);
+    ComputeShaderHash(shader1, a_sha);
+    ComputeShaderHash(shader2, b_sha);
 
     char sha[kHashLength];
     ComputeProgramHash(a_sha,
@@ -58,9 +52,8 @@
   }
 
   void ComputeShaderHash(const std::string& shader,
-                         const ShaderTranslatorInterface* translator,
                          char* result) const {
-    ProgramCache::ComputeShaderHash(shader, translator, result);
+    ProgramCache::ComputeShaderHash(shader, result);
   }
 
   void ComputeProgramHash(const char* hashed_shader_0,
@@ -95,8 +88,8 @@
     std::string shader_b = shader2;
     EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
               cache_->GetLinkedProgramStatus(
-                  shader_a, NULL, shader_b, NULL, NULL));
-    cache_->SaySuccessfullyCached(shader_a, NULL, shader_b, NULL, NULL);
+                  shader_a, shader_b, NULL));
+    cache_->SaySuccessfullyCached(shader_a, shader_b, NULL);
 
     shader_a.clear();
     shader_b.clear();
@@ -104,37 +97,37 @@
   // make sure it was copied
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED,
             cache_->GetLinkedProgramStatus(
-                shader1, NULL, shader2, NULL, NULL));
+                shader1, shader2, NULL));
 }
 
 TEST_F(ProgramCacheTest, LinkUnknownOnFragmentSourceChange) {
   const std::string shader1 = "abcd1234";
   std::string shader2 = "abcda sda b1~#4 bbbbb1234";
-  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
+  cache_->SaySuccessfullyCached(shader1, shader2, NULL);
 
   shader2 = "different!";
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader2, NULL));
 }
 
 TEST_F(ProgramCacheTest, LinkUnknownOnVertexSourceChange) {
   std::string shader1 = "abcd1234";
   const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
-  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
+  cache_->SaySuccessfullyCached(shader1, shader2, NULL);
 
   shader1 = "different!";
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader2, NULL));
 }
 
 TEST_F(ProgramCacheTest, StatusEviction) {
   const std::string shader1 = "abcd1234";
   const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
-  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
+  cache_->SaySuccessfullyCached(shader1, shader2, NULL);
   char a_sha[ProgramCache::kHashLength];
   char b_sha[ProgramCache::kHashLength];
-  cache_->ComputeShaderHash(shader1, NULL, a_sha);
-  cache_->ComputeShaderHash(shader2, NULL, b_sha);
+  cache_->ComputeShaderHash(shader1, a_sha);
+  cache_->ComputeShaderHash(shader2, b_sha);
 
   char sha[ProgramCache::kHashLength];
   cache_->ComputeProgramHash(a_sha,
@@ -143,22 +136,22 @@
                              sha);
   cache_->Evict(std::string(sha, ProgramCache::kHashLength));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader2, NULL));
 }
 
 TEST_F(ProgramCacheTest, EvictionWithReusedShader) {
   const std::string shader1 = "abcd1234";
   const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
   const std::string shader3 = "asbjbbjj239a";
-  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
-  cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL);
+  cache_->SaySuccessfullyCached(shader1, shader2, NULL);
+  cache_->SaySuccessfullyCached(shader1, shader3, NULL);
 
   char a_sha[ProgramCache::kHashLength];
   char b_sha[ProgramCache::kHashLength];
   char c_sha[ProgramCache::kHashLength];
-  cache_->ComputeShaderHash(shader1, NULL, a_sha);
-  cache_->ComputeShaderHash(shader2, NULL, b_sha);
-  cache_->ComputeShaderHash(shader3, NULL, c_sha);
+  cache_->ComputeShaderHash(shader1, a_sha);
+  cache_->ComputeShaderHash(shader2, b_sha);
+  cache_->ComputeShaderHash(shader3, c_sha);
 
   char sha[ProgramCache::kHashLength];
   cache_->ComputeProgramHash(a_sha,
@@ -167,9 +160,9 @@
                              sha);
   cache_->Evict(std::string(sha, ProgramCache::kHashLength));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader2, NULL));
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader3, NULL));
 
 
   cache_->ComputeProgramHash(a_sha,
@@ -178,22 +171,22 @@
                              sha);
   cache_->Evict(std::string(sha, ProgramCache::kHashLength));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader2, NULL));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader3, NULL));
 }
 
 TEST_F(ProgramCacheTest, StatusClear) {
   const std::string shader1 = "abcd1234";
   const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
   const std::string shader3 = "asbjbbjj239a";
-  cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
-  cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL);
+  cache_->SaySuccessfullyCached(shader1, shader2, NULL);
+  cache_->SaySuccessfullyCached(shader1, shader3, NULL);
   cache_->Clear();
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader2, NULL));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
-            cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
+            cache_->GetLinkedProgramStatus(shader1, shader3, NULL));
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 1f6b2d4..aef7e44 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -24,7 +24,6 @@
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "gpu/command_buffer/service/program_cache.h"
 #include "gpu/command_buffer/service/shader_manager.h"
-#include "gpu/command_buffer/service/shader_translator.h"
 #include "third_party/re2/re2/re2.h"
 
 using base::TimeDelta;
@@ -515,48 +514,14 @@
 }
 
 bool Program::Link(ShaderManager* manager,
-                   ShaderTranslator* vertex_translator,
-                   ShaderTranslator* fragment_translator,
                    Program::VaryingsPackingOption varyings_packing_option,
                    const ShaderCacheCallback& shader_callback) {
   ClearLinkStatus();
-  if (!CanLink()) {
+
+  if (!AttachedShadersExist()) {
     set_log_info("missing shaders");
     return false;
   }
-  if (DetectAttribLocationBindingConflicts()) {
-    set_log_info("glBindAttribLocation() conflicts");
-    return false;
-  }
-  std::string conflicting_name;
-  if (DetectUniformsMismatch(&conflicting_name)) {
-    std::string info_log = "Uniforms with the same name but different "
-                           "type/precision: " + conflicting_name;
-    set_log_info(ProcessLogInfo(info_log).c_str());
-    return false;
-  }
-  if (DetectVaryingsMismatch(&conflicting_name)) {
-    std::string info_log = "Varyings with the same name but different type, "
-                           "or statically used varyings in fragment shader are "
-                           "not declared in vertex shader: " + conflicting_name;
-    set_log_info(ProcessLogInfo(info_log).c_str());
-    return false;
-  }
-  if (DetectBuiltInInvariantConflicts()) {
-    set_log_info("Invariant settings for certain built-in varyings "
-                 "have to match");
-    return false;
-  }
-  if (DetectGlobalNameConflicts(&conflicting_name)) {
-    std::string info_log = "Name conflicts between an uniform and an "
-                           "attribute: " + conflicting_name;
-    set_log_info(ProcessLogInfo(info_log).c_str());
-    return false;
-  }
-  if (!CheckVaryingsPacking(varyings_packing_option)) {
-    set_log_info("Varyings over maximum register limit");
-    return false;
-  }
 
   TimeTicks before_time = TimeTicks::Now();
   bool link = true;
@@ -565,19 +530,15 @@
     DCHECK(!attached_shaders_[0]->last_compiled_source().empty() &&
            !attached_shaders_[1]->last_compiled_source().empty());
     ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
-        attached_shaders_[0]->last_compiled_source(),
-        vertex_translator,
-        attached_shaders_[1]->last_compiled_source(),
-        fragment_translator,
+        attached_shaders_[0]->last_compiled_signature(),
+        attached_shaders_[1]->last_compiled_signature(),
         &bind_attrib_location_map_);
 
     if (status == ProgramCache::LINK_SUCCEEDED) {
       ProgramCache::ProgramLoadResult success =
           cache->LoadLinkedProgram(service_id(),
                                    attached_shaders_[0].get(),
-                                   vertex_translator,
                                    attached_shaders_[1].get(),
-                                   fragment_translator,
                                    &bind_attrib_location_map_,
                                    shader_callback);
       link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
@@ -586,6 +547,47 @@
   }
 
   if (link) {
+    CompileAttachedShaders();
+
+    if (!CanLink()) {
+      set_log_info("invalid shaders");
+      return false;
+    }
+    if (DetectAttribLocationBindingConflicts()) {
+      set_log_info("glBindAttribLocation() conflicts");
+      return false;
+    }
+    std::string conflicting_name;
+    if (DetectUniformsMismatch(&conflicting_name)) {
+      std::string info_log = "Uniforms with the same name but different "
+                             "type/precision: " + conflicting_name;
+      set_log_info(ProcessLogInfo(info_log).c_str());
+      return false;
+    }
+    if (DetectVaryingsMismatch(&conflicting_name)) {
+      std::string info_log = "Varyings with the same name but different type, "
+                             "or statically used varyings in fragment shader "
+                             "are not declared in vertex shader: " +
+                             conflicting_name;
+      set_log_info(ProcessLogInfo(info_log).c_str());
+      return false;
+    }
+    if (DetectBuiltInInvariantConflicts()) {
+      set_log_info("Invariant settings for certain built-in varyings "
+                   "have to match");
+      return false;
+    }
+    if (DetectGlobalNameConflicts(&conflicting_name)) {
+      std::string info_log = "Name conflicts between an uniform and an "
+                             "attribute: " + conflicting_name;
+      set_log_info(ProcessLogInfo(info_log).c_str());
+      return false;
+    }
+    if (!CheckVaryingsPacking(varyings_packing_option)) {
+      set_log_info("Varyings over maximum register limit");
+      return false;
+    }
+
     ExecuteBindAttribLocationCalls();
     before_time = TimeTicks::Now();
     if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
@@ -604,9 +606,7 @@
       if (cache) {
         cache->SaveLinkedProgram(service_id(),
                                  attached_shaders_[0].get(),
-                                 vertex_translator,
                                  attached_shaders_[1].get(),
-                                 fragment_translator,
                                  &bind_attrib_location_map_,
                                  shader_callback);
       }
@@ -1001,6 +1001,23 @@
   }
 }
 
+void Program::CompileAttachedShaders() {
+  for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+    Shader* shader = attached_shaders_[ii].get();
+    if (shader) {
+      shader->DoCompile();
+    }
+  }
+}
+
+bool Program::AttachedShadersExist() const {
+  for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+    if (!attached_shaders_[ii].get())
+      return false;
+  }
+  return true;
+}
+
 bool Program::CanLink() const {
   for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
     if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid()) {
@@ -1303,6 +1320,7 @@
   GLuint program = service_id();
 
   uint32_t header_size = sizeof(UniformBlocksHeader);
+  bucket->SetSize(header_size);  // In case we fail.
 
   uint32_t num_uniform_blocks = 0;
   GLint param = GL_FALSE;
@@ -1316,10 +1334,6 @@
   if (num_uniform_blocks == 0) {
     // Although spec allows an implementation to return uniform block info
     // even if a link fails, for consistency, we disallow that.
-    bucket->SetSize(header_size);
-    UniformBlocksHeader* header =
-        bucket->GetDataAs<UniformBlocksHeader*>(0, header_size);
-    header->num_uniform_blocks = 0;
     return true;
   }
 
@@ -1390,7 +1404,7 @@
 
   bucket->SetSize(total_size);
   UniformBlocksHeader* header =
-      bucket->GetDataAs<UniformBlocksHeader*>(0, total_size);
+      bucket->GetDataAs<UniformBlocksHeader*>(0, header_size);
   UniformBlockInfo* entries = bucket->GetDataAs<UniformBlockInfo*>(
       header_size, entry_size);
   char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size);
@@ -1405,8 +1419,8 @@
   std::vector<GLint> params;
   for (uint32_t ii = 0; ii < num_uniform_blocks; ++ii) {
     // Get active uniform name.
-    memcpy(data, names[ii].c_str(), blocks[ii].name_length);
-    data += blocks[ii].name_length;
+    memcpy(data, names[ii].c_str(), names[ii].length() + 1);
+    data += names[ii].length() + 1;
 
     // Get active uniform indices.
     if (params.size() < blocks[ii].active_uniforms)
@@ -1425,6 +1439,170 @@
   return true;
 }
 
+bool Program::GetTransformFeedbackVaryings(
+    CommonDecoder::Bucket* bucket) const {
+  // The data is packed into the bucket in the following order
+  //   1) header
+  //   2) N entries of varying data (except for name)
+  //   3) name1, name2, ..., nameN
+  //
+  // We query all the data directly through GL calls, assuming they are
+  // cheap through MANGLE.
+
+  DCHECK(bucket);
+  GLuint program = service_id();
+
+  uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader);
+  bucket->SetSize(header_size);  // In case we fail.
+
+  uint32_t num_transform_feedback_varyings = 0;
+  GLint param = GL_FALSE;
+  // We assume program is a valid program service id.
+  glGetProgramiv(program, GL_LINK_STATUS, &param);
+  if (param == GL_TRUE) {
+    param = 0;
+    glGetProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &param);
+    num_transform_feedback_varyings = static_cast<uint32_t>(param);
+  }
+  if (num_transform_feedback_varyings == 0) {
+    return true;
+  }
+
+  std::vector<TransformFeedbackVaryingInfo> varyings(
+      num_transform_feedback_varyings);
+  base::CheckedNumeric<uint32_t> size = sizeof(TransformFeedbackVaryingInfo);
+  size *= num_transform_feedback_varyings;
+  uint32_t entry_size = size.ValueOrDefault(0);
+  size += header_size;
+  std::vector<std::string> names(num_transform_feedback_varyings);
+  GLint max_name_length = 0;
+  glGetProgramiv(
+      program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &max_name_length);
+  if (max_name_length < 1)
+    max_name_length = 1;
+  std::vector<char> buffer(max_name_length);
+  for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) {
+    GLsizei var_size = 0;
+    GLsizei var_name_length = 0;
+    GLenum var_type = 0;
+    glGetTransformFeedbackVarying(
+        program, ii, max_name_length,
+        &var_name_length, &var_size, &var_type, &buffer[0]);
+    varyings[ii].size = static_cast<uint32_t>(var_size);
+    varyings[ii].type = static_cast<uint32_t>(var_type);
+    varyings[ii].name_offset = static_cast<uint32_t>(size.ValueOrDefault(0));
+    DCHECK_GT(max_name_length, var_name_length);
+    names[ii] = std::string(&buffer[0], var_name_length);
+    // TODO(zmo): optimize the name mapping lookup.
+    const std::string* original_name = GetOriginalNameFromHashedName(names[ii]);
+    if (original_name)
+      names[ii] = *original_name;
+    varyings[ii].name_length = names[ii].size() + 1;
+    size += names[ii].size();
+    size += 1;
+  }
+  if (!size.IsValid())
+    return false;
+  uint32_t total_size = size.ValueOrDefault(0);
+  DCHECK_LE(header_size + entry_size, total_size);
+  uint32_t data_size = total_size - header_size - entry_size;
+
+  bucket->SetSize(total_size);
+  TransformFeedbackVaryingsHeader* header =
+      bucket->GetDataAs<TransformFeedbackVaryingsHeader*>(0, header_size);
+  TransformFeedbackVaryingInfo* entries =
+      bucket->GetDataAs<TransformFeedbackVaryingInfo*>(header_size, entry_size);
+  char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size);
+  DCHECK(header);
+  DCHECK(entries);
+  DCHECK(data);
+
+  // Copy over data for the header and entries.
+  header->num_transform_feedback_varyings = num_transform_feedback_varyings;
+  memcpy(entries, &varyings[0], entry_size);
+
+  for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) {
+    memcpy(data, names[ii].c_str(), names[ii].length() + 1);
+    data += names[ii].length() + 1;
+  }
+  DCHECK_EQ(ComputeOffset(header, data), total_size);
+  return true;
+}
+
+bool Program::GetUniformsES3(CommonDecoder::Bucket* bucket) const {
+  // The data is packed into the bucket in the following order
+  //   1) header
+  //   2) N entries of UniformES3Info
+  //
+  // We query all the data directly through GL calls, assuming they are
+  // cheap through MANGLE.
+
+  DCHECK(bucket);
+  GLuint program = service_id();
+
+  uint32_t header_size = sizeof(UniformsES3Header);
+  bucket->SetSize(header_size);  // In case we fail.
+
+  GLsizei count = 0;
+  GLint param = GL_FALSE;
+  // We assume program is a valid program service id.
+  glGetProgramiv(program, GL_LINK_STATUS, &param);
+  if (param == GL_TRUE) {
+    param = 0;
+    glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count);
+  }
+  if (count == 0) {
+    return true;
+  }
+
+  base::CheckedNumeric<uint32_t> size = sizeof(UniformES3Info);
+  size *= count;
+  uint32_t entry_size = size.ValueOrDefault(0);
+  size += header_size;
+  if (!size.IsValid())
+    return false;
+  uint32_t total_size = size.ValueOrDefault(0);
+  bucket->SetSize(total_size);
+  UniformsES3Header* header =
+      bucket->GetDataAs<UniformsES3Header*>(0, header_size);
+  DCHECK(header);
+  header->num_uniforms = static_cast<uint32_t>(count);
+
+  // Instead of GetDataAs<UniformES3Info*>, we do GetDataAs<int32_t>. This is
+  // because struct UniformES3Info is defined as five int32_t.
+  // By doing this, we can fill the structs through loops.
+  int32_t* entries =
+      bucket->GetDataAs<int32_t*>(header_size, entry_size);
+  DCHECK(entries);
+  const size_t kStride = sizeof(UniformES3Info) / sizeof(int32_t);
+
+  const GLenum kPname[] = {
+    GL_UNIFORM_BLOCK_INDEX,
+    GL_UNIFORM_OFFSET,
+    GL_UNIFORM_ARRAY_STRIDE,
+    GL_UNIFORM_MATRIX_STRIDE,
+    GL_UNIFORM_IS_ROW_MAJOR,
+  };
+  const GLint kDefaultValue[] = { -1, -1, -1, -1, 0 };
+  const size_t kNumPnames = arraysize(kPname);
+  std::vector<GLuint> indices(count);
+  for (GLsizei ii = 0; ii < count; ++ii) {
+    indices[ii] = ii;
+  }
+  std::vector<GLint> params(count);
+  for (size_t pname_index = 0; pname_index < kNumPnames; ++pname_index) {
+    for (GLsizei ii = 0; ii < count; ++ii) {
+      params[ii] = kDefaultValue[pname_index];
+    }
+    glGetActiveUniformsiv(
+        program, count, &indices[0], kPname[pname_index], &params[0]);
+    for (GLsizei ii = 0; ii < count; ++ii) {
+      entries[kStride * ii + pname_index] = params[ii];
+    }
+  }
+  return true;
+}
+
 Program::~Program() {
   if (manager_) {
     if (manager_->have_context_) {
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 6f7e3a9..b8b2d2d 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -24,7 +24,6 @@
 class ProgramManager;
 class Shader;
 class ShaderManager;
-class ShaderTranslator;
 
 // This is used to track which attributes a particular program needs
 // so we can verify at glDrawXXX time that every attribute is either disabled
@@ -153,6 +152,15 @@
   // Return false on overflow.
   bool GetUniformBlocks(CommonDecoder::Bucket* bucket) const;
 
+  // Gets all the TransformFeedbackVarying info.
+  // Return false on overflow.
+  bool GetTransformFeedbackVaryings(CommonDecoder::Bucket* bucket) const;
+
+  // Gather all info through glGetActiveUniformsiv, except for size, type,
+  // name_length, which we gather through glGetActiveUniform in
+  // glGetProgramInfoCHROMIUM.
+  bool GetUniformsES3(CommonDecoder::Bucket* bucket) const;
+
   // Sets the sampler values for a uniform.
   // This is safe to call for any location. If the location is not
   // a sampler uniform nothing will happen.
@@ -175,12 +183,12 @@
   bool AttachShader(ShaderManager* manager, Shader* shader);
   bool DetachShader(ShaderManager* manager, Shader* shader);
 
+  void CompileAttachedShaders();
+  bool AttachedShadersExist() const;
   bool CanLink() const;
 
   // Performs glLinkProgram and related activities.
   bool Link(ShaderManager* manager,
-            ShaderTranslator* vertex_translator,
-            ShaderTranslator* fragment_shader,
             VaryingsPackingOption varyings_packing_option,
             const ShaderCacheCallback& shader_callback);
 
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 7d9ea9d..99678f4 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -242,7 +242,7 @@
 
     program_->AttachShader(&shader_manager_, vertex_shader);
     program_->AttachShader(&shader_manager_, fragment_shader);
-    program_->Link(NULL, NULL, NULL, Program::kCountOnlyStaticallyUsed,
+    program_->Link(NULL, Program::kCountOnlyStaticallyUsed,
                    base::Bind(&ShaderCacheCb));
   }
 
@@ -272,7 +272,7 @@
       SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
                   service_id);
     }
-    program->Link(NULL, NULL, NULL, Program::kCountOnlyStaticallyUsed,
+    program->Link(NULL, Program::kCountOnlyStaticallyUsed,
                   base::Bind(&ShaderCacheCb));
     GLint link_status;
     program->GetProgramiv(GL_LINK_STATUS, &link_status);
@@ -715,7 +715,7 @@
   ASSERT_TRUE(program != NULL);
   EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
   EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
-  program->Link(NULL, NULL, NULL, Program::kCountOnlyStaticallyUsed,
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
                 base::Bind(&ShaderCacheCb));
   GLint value = 0;
   program->GetProgramiv(GL_ACTIVE_ATTRIBUTES, &value);
@@ -784,7 +784,7 @@
   ASSERT_TRUE(program != NULL);
   EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
   EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
-  program->Link(NULL, NULL, NULL, Program::kCountOnlyStaticallyUsed,
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
                 base::Bind(&ShaderCacheCb));
 
   // Check that we get the correct locations.
@@ -880,7 +880,7 @@
   ASSERT_TRUE(program!= NULL);
   EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
   EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
-  program->Link(NULL, NULL, NULL, Program::kCountOnlyStaticallyUsed,
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
                 base::Bind(&ShaderCacheCb));
   // Check that we got the good type, not the bad.
   // Check Attribs
@@ -1227,6 +1227,199 @@
   EXPECT_EQ(0, memcmp(&data, bucket_data, sizeof(Data)));
 }
 
+TEST_F(ProgramManagerWithShaderTest,
+       ProgramInfoGetTransformFeedbackVaryingsNone) {
+  CommonDecoder::Bucket bucket;
+  const Program* program = manager_.GetProgram(kClientProgramId);
+  ASSERT_TRUE(program != NULL);
+  // The program's previous link failed.
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_FALSE))
+      .RetiresOnSaturation();
+  EXPECT_TRUE(program->GetTransformFeedbackVaryings(&bucket));
+  EXPECT_EQ(sizeof(TransformFeedbackVaryingsHeader), bucket.size());
+  TransformFeedbackVaryingsHeader* header =
+      bucket.GetDataAs<TransformFeedbackVaryingsHeader*>(
+          0, sizeof(TransformFeedbackVaryingsHeader));
+  EXPECT_TRUE(header != NULL);
+  EXPECT_EQ(0u, header->num_transform_feedback_varyings);
+  // Zero uniform blocks.
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(
+                  kServiceProgramId, GL_TRANSFORM_FEEDBACK_VARYINGS, _))
+      .WillOnce(SetArgPointee<2>(0))
+      .RetiresOnSaturation();
+  EXPECT_TRUE(program->GetTransformFeedbackVaryings(&bucket));
+  EXPECT_EQ(sizeof(TransformFeedbackVaryingsHeader), bucket.size());
+  header = bucket.GetDataAs<TransformFeedbackVaryingsHeader*>(
+      0, sizeof(TransformFeedbackVaryingsHeader));
+  EXPECT_TRUE(header != NULL);
+  EXPECT_EQ(0u, header->num_transform_feedback_varyings);
+}
+
+TEST_F(ProgramManagerWithShaderTest,
+       ProgramInfoGetTransformFeedbackVaryingsValid) {
+  CommonDecoder::Bucket bucket;
+  const Program* program = manager_.GetProgram(kClientProgramId);
+  ASSERT_TRUE(program != NULL);
+  struct Data {
+    TransformFeedbackVaryingsHeader header;
+    TransformFeedbackVaryingInfo entry[2];
+    char name0[4];
+    char name1[8];
+  };
+  Data data;
+  // The names needs to be of size 4*k-1 to avoid padding in the struct Data.
+  // This is a testing only problem.
+  const char* kName[] = { "cow", "chicken" };
+  data.header.num_transform_feedback_varyings = 2;
+  data.entry[0].size = 1;
+  data.entry[0].type = GL_FLOAT_VEC2;
+  data.entry[0].name_offset = ComputeOffset(&data, data.name0);
+  data.entry[0].name_length = arraysize(data.name0);
+  data.entry[1].size = 2;
+  data.entry[1].type = GL_FLOAT;
+  data.entry[1].name_offset = ComputeOffset(&data, data.name1);
+  data.entry[1].name_length = arraysize(data.name1);
+  memcpy(data.name0, kName[0], arraysize(data.name0));
+  memcpy(data.name1, kName[1], arraysize(data.name1));
+
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(
+                  kServiceProgramId, GL_TRANSFORM_FEEDBACK_VARYINGS, _))
+      .WillOnce(SetArgPointee<2>(data.header.num_transform_feedback_varyings))
+      .RetiresOnSaturation();
+  GLsizei max_length = 1 + std::max(strlen(kName[0]), strlen(kName[1]));
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId,
+                           GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, _))
+      .WillOnce(SetArgPointee<2>(max_length))
+      .RetiresOnSaturation();
+  for (uint32_t ii = 0; ii < data.header.num_transform_feedback_varyings;
+       ++ii) {
+    EXPECT_CALL(*(gl_.get()),
+                GetTransformFeedbackVarying(
+                    kServiceProgramId, ii, max_length, _, _, _, _))
+        .WillOnce(DoAll(
+            SetArgPointee<3>(data.entry[ii].name_length - 1),
+            SetArgPointee<4>(data.entry[ii].size),
+            SetArgPointee<5>(data.entry[ii].type),
+            SetArrayArgument<6>(
+                kName[ii], kName[ii] + data.entry[ii].name_length)))
+        .RetiresOnSaturation();
+  }
+  program->GetTransformFeedbackVaryings(&bucket);
+  EXPECT_EQ(sizeof(Data), bucket.size());
+  Data* bucket_data = bucket.GetDataAs<Data*>(0, sizeof(Data));
+  EXPECT_TRUE(bucket_data != NULL);
+  EXPECT_EQ(0, memcmp(&data, bucket_data, sizeof(Data)));
+}
+
+TEST_F(ProgramManagerWithShaderTest, ProgramInfoGetUniformsES3None) {
+  CommonDecoder::Bucket bucket;
+  const Program* program = manager_.GetProgram(kClientProgramId);
+  ASSERT_TRUE(program != NULL);
+  // The program's previous link failed.
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_FALSE))
+      .RetiresOnSaturation();
+  EXPECT_TRUE(program->GetUniformsES3(&bucket));
+  EXPECT_EQ(sizeof(UniformsES3Header), bucket.size());
+  UniformsES3Header* header =
+      bucket.GetDataAs<UniformsES3Header*>(0, sizeof(UniformsES3Header));
+  EXPECT_TRUE(header != NULL);
+  EXPECT_EQ(0u, header->num_uniforms);
+  // Zero uniform blocks.
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORMS, _))
+      .WillOnce(SetArgPointee<2>(0))
+      .RetiresOnSaturation();
+  EXPECT_TRUE(program->GetUniformsES3(&bucket));
+  EXPECT_EQ(sizeof(UniformsES3Header), bucket.size());
+  header =
+      bucket.GetDataAs<UniformsES3Header*>(0, sizeof(UniformsES3Header));
+  EXPECT_TRUE(header != NULL);
+  EXPECT_EQ(0u, header->num_uniforms);
+}
+
+TEST_F(ProgramManagerWithShaderTest, ProgramInfoGetUniformsES3Valid) {
+  CommonDecoder::Bucket bucket;
+  const Program* program = manager_.GetProgram(kClientProgramId);
+  ASSERT_TRUE(program != NULL);
+  struct Data {
+    UniformsES3Header header;
+    UniformES3Info entry[2];
+  };
+  Data data;
+  const GLint kBlockIndex[] = { -1, 2 };
+  const GLint kOffset[] = { 3, 4 };
+  const GLint kArrayStride[] = { 7, 8 };
+  const GLint kMatrixStride[] = { 9, 10 };
+  const GLint kIsRowMajor[] = { 0, 1 };
+  data.header.num_uniforms = 2;
+  for (uint32_t ii = 0; ii < data.header.num_uniforms; ++ii) {
+    data.entry[ii].block_index = kBlockIndex[ii];
+    data.entry[ii].offset = kOffset[ii];
+    data.entry[ii].array_stride = kArrayStride[ii];
+    data.entry[ii].matrix_stride = kMatrixStride[ii];
+    data.entry[ii].is_row_major = kIsRowMajor[ii];
+  }
+
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgPointee<2>(GL_TRUE))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*(gl_.get()),
+              GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORMS, _))
+      .WillOnce(SetArgPointee<2>(data.header.num_uniforms))
+      .RetiresOnSaturation();
+
+  const GLenum kPname[] = {
+    GL_UNIFORM_BLOCK_INDEX,
+    GL_UNIFORM_OFFSET,
+    GL_UNIFORM_ARRAY_STRIDE,
+    GL_UNIFORM_MATRIX_STRIDE,
+    GL_UNIFORM_IS_ROW_MAJOR,
+  };
+  const GLint* kParams[] = {
+    kBlockIndex,
+    kOffset,
+    kArrayStride,
+    kMatrixStride,
+    kIsRowMajor,
+  };
+  const size_t kNumIterations = arraysize(kPname);
+  for (size_t ii = 0; ii < kNumIterations; ++ii) {
+    EXPECT_CALL(*(gl_.get()),
+                GetActiveUniformsiv(
+                    kServiceProgramId, data.header.num_uniforms, _,
+                    kPname[ii], _))
+      .WillOnce(SetArrayArgument<4>(
+          kParams[ii], kParams[ii] + data.header.num_uniforms))
+      .RetiresOnSaturation();
+  }
+
+  program->GetUniformsES3(&bucket);
+  EXPECT_EQ(sizeof(Data), bucket.size());
+  Data* bucket_data = bucket.GetDataAs<Data*>(0, sizeof(Data));
+  EXPECT_TRUE(bucket_data != NULL);
+  EXPECT_EQ(0, memcmp(&data, bucket_data, sizeof(Data)));
+}
+
 // Some drivers optimize out unused uniform array elements, so their
 // location would be -1.
 TEST_F(ProgramManagerWithShaderTest, UnusedUniformArrayElements) {
@@ -1631,7 +1824,7 @@
     const size_t kNumUniforms = arraysize(kUniforms);
     SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
                 kServiceProgramId);
-    program->Link(NULL, NULL, NULL, Program::kCountOnlyStaticallyUsed,
+    program->Link(NULL, Program::kCountOnlyStaticallyUsed,
                   base::Bind(&ShaderCacheCb));
     SetupExpectationsForClearingUniforms(kUniforms, kNumUniforms);
     manager_.ClearUniforms(program);
@@ -1704,7 +1897,7 @@
   const size_t kNumUniforms = arraysize(kUniforms);
   SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
               kServiceProgramId);
-  program->Link(NULL, NULL, NULL, Program::kCountOnlyStaticallyUsed,
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
                 base::Bind(&ShaderCacheCb));
 
   EXPECT_EQ(kUniform1DesiredLocation,
@@ -1765,9 +1958,7 @@
   void SetProgramCached() {
     cache_->LinkedProgramCacheSuccess(
         vertex_shader_->source(),
-        NULL,
         fragment_shader_->source(),
-        NULL,
         &program_->bind_attrib_location_map());
   }
 
@@ -1784,9 +1975,7 @@
     EXPECT_CALL(*cache_.get(), SaveLinkedProgram(
         program->service_id(),
         vertex_shader,
-        NULL,
         fragment_shader,
-        NULL,
         &program->bind_attrib_location_map(),
         _)).Times(1);
   }
@@ -1804,9 +1993,7 @@
     EXPECT_CALL(*cache_.get(), SaveLinkedProgram(
         program->service_id(),
         vertex_shader,
-        NULL,
         fragment_shader,
-        NULL,
         &program->bind_attrib_location_map(),
         _)).Times(0);
   }
@@ -1828,9 +2015,7 @@
     EXPECT_CALL(*cache_.get(),
                 LoadLinkedProgram(service_program_id,
                                   vertex_shader,
-                                  NULL,
                                   fragment_shader,
-                                  NULL,
                                   &program->bind_attrib_location_map(),
                                   _))
         .WillOnce(Return(result));
@@ -1921,8 +2106,8 @@
   SetShadersCompiled();
   SetExpectationsForProgramLink();
   SetExpectationsForProgramCached();
-  EXPECT_TRUE(program_->Link(NULL, NULL, NULL,
-      Program::kCountOnlyStaticallyUsed, base::Bind(&ShaderCacheCb)));
+  EXPECT_TRUE(program_->Link(NULL, Program::kCountOnlyStaticallyUsed,
+                             base::Bind(&ShaderCacheCb)));
 }
 
 TEST_F(ProgramManagerWithCacheTest, LoadProgramOnProgramCacheHit) {
@@ -1935,8 +2120,8 @@
   SetExpectationsForNotCachingProgram();
   SetExpectationsForProgramLoadSuccess();
 
-  EXPECT_TRUE(program_->Link(NULL, NULL, NULL,
-      Program::kCountOnlyStaticallyUsed, base::Bind(&ShaderCacheCb)));
+  EXPECT_TRUE(program_->Link(NULL, Program::kCountOnlyStaticallyUsed,
+                             base::Bind(&ShaderCacheCb)));
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index 90b1576..055cd70 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -29,19 +29,22 @@
         shader_state_(kShaderStateWaiting),
         service_id_(service_id),
         shader_type_(shader_type),
+        source_type_(kANGLE),
         valid_(false) {
 }
 
 Shader::~Shader() {
 }
 
-void Shader::RequestCompile() {
+void Shader::RequestCompile(scoped_refptr<ShaderTranslatorInterface> translator,
+                            TranslatedShaderSourceType type) {
   shader_state_ = kShaderStateCompileRequested;
+  translator_ = translator;
+  source_type_ = type;
   last_compiled_source_ = source_;
 }
 
-void Shader::DoCompile(ShaderTranslatorInterface* translator,
-                       TranslatedShaderSourceType type) {
+void Shader::DoCompile() {
   // We require that RequestCompile() must be called before DoCompile(),
   // so we can return early if the shader state is not what we expect.
   if (shader_state_ != kShaderStateCompileRequested) {
@@ -51,19 +54,21 @@
   // Signify the shader has been compiled, whether or not it is valid
   // is dependent on the |valid_| member variable.
   shader_state_ = kShaderStateCompiled;
+  valid_ = false;
 
   // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
   // glShaderSource and then glCompileShader.
   const char* source_for_driver = last_compiled_source_.c_str();
+  ShaderTranslatorInterface* translator = translator_.get();
   if (translator) {
-    valid_ = translator->Translate(last_compiled_source_,
-                                   &log_info_,
-                                   &translated_source_,
-                                   &attrib_map_,
-                                   &uniform_map_,
-                                   &varying_map_,
-                                   &name_map_);
-    if (!valid_) {
+    bool success = translator->Translate(last_compiled_source_,
+                                         &log_info_,
+                                         &translated_source_,
+                                         &attrib_map_,
+                                         &uniform_map_,
+                                         &varying_map_,
+                                         &name_map_);
+    if (!success) {
       return;
     }
     source_for_driver = translated_source_.c_str();
@@ -71,7 +76,7 @@
 
   glShaderSource(service_id_, 1, &source_for_driver, NULL);
   glCompileShader(service_id_);
-  if (type == kANGLE) {
+  if (source_type_ == kANGLE) {
     GLint max_len = 0;
     glGetShaderiv(service_id_,
                   GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
@@ -84,11 +89,14 @@
     DCHECK(max_len == 0 || len < max_len);
     DCHECK(len == 0 || translated_source_[len] == '\0');
     translated_source_.resize(len);
+    source_for_driver = translated_source_.c_str();
   }
 
   GLint status = GL_FALSE;
   glGetShaderiv(service_id_, GL_COMPILE_STATUS, &status);
-  if (status != GL_TRUE) {
+  if (status == GL_TRUE) {
+    valid_ = true;
+  } else {
     // We cannot reach here if we are using the shader translator.
     // All invalid shaders must be rejected by the translator.
     // All translated shaders must compile.
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h
index 11f567d..82fd288 100644
--- a/gpu/command_buffer/service/shader_manager.h
+++ b/gpu/command_buffer/service/shader_manager.h
@@ -35,10 +35,10 @@
     kShaderStateCompiled, // Signifies compile happened, not valid compile.
   };
 
-  void RequestCompile();
+  void RequestCompile(scoped_refptr<ShaderTranslatorInterface> translator,
+                      TranslatedShaderSourceType type);
 
-  void DoCompile(ShaderTranslatorInterface* translator,
-                 TranslatedShaderSourceType type);
+  void DoCompile();
 
   ShaderState shader_state() const {
     return shader_state_;
@@ -64,7 +64,15 @@
     return translated_source_;
   }
 
-  const std::string& last_compiled_source() const {
+  std::string last_compiled_source() const {
+    return last_compiled_source_;
+  }
+
+  std::string last_compiled_signature() const {
+    if (translator_.get()) {
+      return last_compiled_source_ +
+             translator_->GetStringForOptionsThatWouldAffectCompilation();
+    }
     return last_compiled_source_;
   }
 
@@ -152,6 +160,12 @@
   // Type of shader - GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
   GLenum shader_type_;
 
+  // Translated source type when shader was last requested to be compiled.
+  TranslatedShaderSourceType source_type_;
+
+  // Translator to use, set when shader was last requested to be compiled.
+  scoped_refptr<ShaderTranslatorInterface> translator_;
+
   // True if compilation succeeded.
   bool valid_;
 
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc
index f5f6206..c46b734 100644
--- a/gpu/command_buffer/service/shader_manager_unittest.cc
+++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -140,14 +140,14 @@
   EXPECT_TRUE(shader1->last_compiled_source().empty());
 
   // Check that DoCompile() will not work if RequestCompile() was not called.
-  MockShaderTranslator translator;
-  shader1->DoCompile(&translator, Shader::kANGLE);
+  shader1->DoCompile();
   EXPECT_EQ(Shader::kShaderStateWaiting, shader1->shader_state());
   EXPECT_FALSE(shader1->valid());
 
   // Check RequestCompile() will update the state and last compiled source, but
   // still keep the actual compile state invalid.
-  shader1->RequestCompile();
+  scoped_refptr<ShaderTranslatorInterface> translator(new MockShaderTranslator);
+  shader1->RequestCompile(translator, Shader::kANGLE);
   EXPECT_EQ(Shader::kShaderStateCompileRequested, shader1->shader_state());
   EXPECT_STREQ(kClient1Source, shader1->last_compiled_source().c_str());
   EXPECT_FALSE(shader1->valid());
diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h
index ef25ebb..818be5d 100644
--- a/gpu/command_buffer/service/shader_translator.h
+++ b/gpu/command_buffer/service/shader_translator.h
@@ -27,8 +27,10 @@
 
 // Translates a GLSL ES 2.0 shader to desktop GLSL shader, or just
 // validates GLSL ES 2.0 shaders on a true GLSL ES implementation.
-class ShaderTranslatorInterface {
+class ShaderTranslatorInterface
+    : public base::RefCounted<ShaderTranslatorInterface> {
  public:
+  ShaderTranslatorInterface() {}
   enum GlslImplementationType {
     kGlsl,
     kGlslES
@@ -62,12 +64,15 @@
 
  protected:
   virtual ~ShaderTranslatorInterface() {}
+
+ private:
+  friend class base::RefCounted<ShaderTranslatorInterface>;
+  DISALLOW_COPY_AND_ASSIGN(ShaderTranslatorInterface);
 };
 
 // Implementation of ShaderTranslatorInterface
 class GPU_EXPORT ShaderTranslator
-    : public base::RefCounted<ShaderTranslator>,
-      NON_EXPORTED_BASE(public ShaderTranslatorInterface) {
+    : NON_EXPORTED_BASE(public ShaderTranslatorInterface) {
  public:
   class DestructionObserver {
    public:
@@ -104,17 +109,14 @@
   void RemoveDestructionObserver(DestructionObserver* observer);
 
  private:
-  friend class base::RefCounted<ShaderTranslator>;
-
   ~ShaderTranslator() override;
+
   int GetCompileOptions() const;
 
   ShHandle compiler_;
   bool implementation_is_glsl_es_;
   ShCompileOptions driver_bug_workarounds_;
   ObserverList<DestructionObserver> destruction_observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShaderTranslator);
 };
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/sync_point_manager.cc b/gpu/command_buffer/service/sync_point_manager.cc
index cd8c490..aa91bf1 100644
--- a/gpu/command_buffer/service/sync_point_manager.cc
+++ b/gpu/command_buffer/service/sync_point_manager.cc
@@ -8,16 +8,26 @@
 
 #include "base/logging.h"
 #include "base/rand_util.h"
+#include "base/sequence_checker.h"
 
 namespace gpu {
 
 static const int kMaxSyncBase = INT_MAX;
 
-SyncPointManager::SyncPointManager()
+// static
+SyncPointManager* SyncPointManager::Create(bool allow_threaded_calls) {
+  return new SyncPointManager(allow_threaded_calls);
+}
+
+SyncPointManager::SyncPointManager(bool allow_threaded_calls)
     : next_sync_point_(base::RandInt(1, kMaxSyncBase)) {
   // To reduce the risk that a sync point created in a previous GPU process
   // will be in flight in the next GPU process, randomize the starting sync
   // point number. http://crbug.com/373452
+
+  if (!allow_threaded_calls) {
+    sequence_checker_.reset(new base::SequenceChecker);
+  }
 }
 
 SyncPointManager::~SyncPointManager() {
@@ -41,7 +51,7 @@
 }
 
 void SyncPointManager::RetireSyncPoint(uint32 sync_point) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  CheckSequencedThread();
   ClosureList list;
   {
     base::AutoLock lock(lock_);
@@ -60,7 +70,7 @@
 
 void SyncPointManager::AddSyncPointCallback(uint32 sync_point,
                                             const base::Closure& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  CheckSequencedThread();
   {
     base::AutoLock lock(lock_);
     SyncPointMap::iterator it = sync_point_map_.find(sync_point);
@@ -73,7 +83,7 @@
 }
 
 bool SyncPointManager::IsSyncPointRetired(uint32 sync_point) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  CheckSequencedThread();
   {
     base::AutoLock lock(lock_);
     SyncPointMap::iterator it = sync_point_map_.find(sync_point);
@@ -81,4 +91,9 @@
   }
 }
 
+void SyncPointManager::CheckSequencedThread() {
+  DCHECK(!sequence_checker_ ||
+         sequence_checker_->CalledOnValidSequencedThread());
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/sync_point_manager.h b/gpu/command_buffer/service/sync_point_manager.h
index 8cbf8a8..001ab17 100644
--- a/gpu/command_buffer/service/sync_point_manager.h
+++ b/gpu/command_buffer/service/sync_point_manager.h
@@ -10,10 +10,14 @@
 #include "base/callback.h"
 #include "base/containers/hash_tables.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
 #include "gpu/gpu_export.h"
 
+namespace base {
+class SequenceChecker;
+}
+
 namespace gpu {
 
 // This class manages the sync points, which allow cross-channel
@@ -21,7 +25,10 @@
 class GPU_EXPORT SyncPointManager
     : public base::RefCountedThreadSafe<SyncPointManager> {
  public:
-  SyncPointManager();
+  // InProcessCommandBuffer allows threaded calls since it can call into
+  // SyncPointManager from client threads, or from multiple service threads
+  // used in Android WebView.
+  static SyncPointManager* Create(bool allow_threaded_calls);
 
   // Generates a sync point, returning its ID. This can me called on any thread.
   // IDs start at a random number. Never return 0.
@@ -44,9 +51,11 @@
   typedef std::vector<base::Closure> ClosureList;
   typedef base::hash_map<uint32, ClosureList> SyncPointMap;
 
+  explicit SyncPointManager(bool allow_threaded_calls);
   ~SyncPointManager();
+  void CheckSequencedThread();
 
-  base::ThreadChecker thread_checker_;
+  scoped_ptr<base::SequenceChecker> sequence_checker_;
 
   // Protects the 2 fields below. Note: callbacks shouldn't be called with this
   // held.
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index 6cd0acf..096a60c 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -761,14 +761,15 @@
   const NameMap* name_map = (expected_name_map && expected_valid) ?
       expected_name_map : &empty_name_map;
 
-  MockShaderTranslator translator;
-  EXPECT_CALL(translator, Translate(_,
-                                    NotNull(),  // log_info
-                                    NotNull(),  // translated_source
-                                    NotNull(),  // attrib_map
-                                    NotNull(),  // uniform_map
-                                    NotNull(),  // varying_map
-                                    NotNull()))  // name_map
+  MockShaderTranslator* mock_translator = new MockShaderTranslator;
+  scoped_refptr<ShaderTranslatorInterface> translator(mock_translator);
+  EXPECT_CALL(*mock_translator, Translate(_,
+                                          NotNull(),  // log_info
+                                          NotNull(),  // translated_source
+                                          NotNull(),  // attrib_map
+                                          NotNull(),  // uniform_map
+                                          NotNull(),  // varying_map
+                                          NotNull()))  // name_map
       .WillOnce(DoAll(SetArgumentPointee<1>(*log_info),
                       SetArgumentPointee<2>(*translated_source),
                       SetArgumentPointee<3>(*attrib_map),
@@ -790,8 +791,8 @@
         .WillOnce(SetArgumentPointee<2>(GL_TRUE))
         .RetiresOnSaturation();
   }
-  shader->RequestCompile();
-  shader->DoCompile(&translator, Shader::kGL);
+  shader->RequestCompile(translator, Shader::kGL);
+  shader->DoCompile();
 }
 
 // static
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 8f4b330..43120b9 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -429,4 +429,8 @@
   return 0;
 }
 
+void GLManager::SetLock(base::Lock*) {
+  NOTIMPLEMENTED();
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index cad1469..c163ac0 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -119,6 +119,7 @@
   void SignalQuery(uint32 query, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
+  void SetLock(base::Lock*) override;
 
  private:
   void PumpCommands();
diff --git a/gpu/command_buffer/tests/gl_program_unittest.cc b/gpu/command_buffer/tests/gl_program_unittest.cc
index 186b28b..d243994 100644
--- a/gpu/command_buffer/tests/gl_program_unittest.cc
+++ b/gpu/command_buffer/tests/gl_program_unittest.cc
@@ -4,7 +4,9 @@
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
 
+#include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/tests/gl_manager.h"
 #include "gpu/command_buffer/tests/gl_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -187,5 +189,67 @@
   GLTestHelper::CheckGLError("no errors", __LINE__);
 }
 
+TEST_F(GLProgramTest, DeferCompileWithExt) {
+  // This test must have extensions enabled.
+  gles2::ContextGroup* context_group = gl_.decoder()->GetContextGroup();
+  gles2::FeatureInfo* feature_info = context_group->feature_info();
+  const gles2::FeatureInfo::FeatureFlags& flags = feature_info->feature_flags();
+  if (!flags.ext_frag_depth)
+    return;
+
+  static const char* v_shdr_str = R"(
+      attribute vec4 vPosition;
+      void main()
+      {
+        gl_Position = vPosition;
+      }
+  )";
+  static const char* f_shdr_str = R"(
+      #extension GL_EXT_frag_depth : enable
+      void main()
+      {
+        gl_FragDepthEXT = 1.0;
+      }
+  )";
+
+  // First compile and link to be shader compiles.
+  GLuint vs_good = GLTestHelper::CompileShader(GL_VERTEX_SHADER, v_shdr_str);
+  GLuint fs_good = GLTestHelper::CompileShader(GL_FRAGMENT_SHADER, f_shdr_str);
+  GLuint program_good = GLTestHelper::LinkProgram(vs_good, fs_good);
+  GLint linked_good = 0;
+  glGetProgramiv(program_good, GL_LINK_STATUS, &linked_good);
+  EXPECT_NE(0, linked_good);
+
+  // Disable extension and be sure shader no longer compiles.
+  ASSERT_TRUE(glEnableFeatureCHROMIUM("webgl_enable_glsl_webgl_validation"));
+  GLuint vs_bad = GLTestHelper::CompileShader(GL_VERTEX_SHADER, v_shdr_str);
+  GLuint fs_bad = GLTestHelper::CompileShader(GL_FRAGMENT_SHADER, f_shdr_str);
+  GLuint program_bad = GLTestHelper::LinkProgram(vs_bad, fs_bad);
+  GLint linked_bad = 0;
+  glGetProgramiv(program_bad, GL_LINK_STATUS, &linked_bad);
+  EXPECT_EQ(0, linked_bad);
+
+  // Relinking good compilations without extension disabled should still link.
+  GLuint program_defer_good = GLTestHelper::LinkProgram(vs_good, fs_good);
+  GLint linked_defer_good = 0;
+  glGetProgramiv(program_defer_good, GL_LINK_STATUS, &linked_defer_good);
+  EXPECT_NE(0, linked_defer_good);
+
+  // linking bad compilations with extension enabled should still not link.
+  GLuint vs_bad2 = GLTestHelper::CompileShader(GL_VERTEX_SHADER, v_shdr_str);
+  GLuint fs_bad2 = GLTestHelper::CompileShader(GL_FRAGMENT_SHADER, f_shdr_str);
+  glRequestExtensionCHROMIUM("GL_EXT_frag_depth");
+  GLuint program_bad2 = GLTestHelper::LinkProgram(vs_bad2, fs_bad2);
+  GLint linked_bad2 = 0;
+  glGetProgramiv(program_bad2, GL_LINK_STATUS, &linked_bad2);
+  EXPECT_EQ(0, linked_bad2);
+
+  // Be sure extension was actually turned on by recompiling.
+  GLuint vs_good2 = GLTestHelper::LoadShader(GL_VERTEX_SHADER, v_shdr_str);
+  GLuint fs_good2 = GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, f_shdr_str);
+  GLuint program_good2 = GLTestHelper::SetupProgram(vs_good2, fs_good2);
+  EXPECT_NE(0u, program_good2);
+}
+
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc
index d3272ca..7582a5d 100644
--- a/gpu/command_buffer/tests/gl_test_utils.cc
+++ b/gpu/command_buffer/tests/gl_test_utils.cc
@@ -31,12 +31,19 @@
    return success;
 }
 
-GLuint GLTestHelper::LoadShader(GLenum type, const char* shaderSrc) {
+GLuint GLTestHelper::CompileShader(GLenum type, const char* shaderSrc) {
   GLuint shader = glCreateShader(type);
   // Load the shader source
   glShaderSource(shader, 1, &shaderSrc, NULL);
   // Compile the shader
   glCompileShader(shader);
+
+  return shader;
+}
+
+GLuint GLTestHelper::LoadShader(GLenum type, const char* shaderSrc) {
+  GLuint shader = CompileShader(type, shaderSrc);
+
   // Check the compile status
   GLint value = 0;
   glGetShaderiv(shader, GL_COMPILE_STATUS, &value);
@@ -52,7 +59,7 @@
   return shader;
 }
 
-GLuint GLTestHelper::SetupProgram(
+GLuint GLTestHelper::LinkProgram(
     GLuint vertex_shader, GLuint fragment_shader) {
   // Create the program object
   GLuint program = glCreateProgram();
@@ -60,6 +67,13 @@
   glAttachShader(program, fragment_shader);
   // Link the program
   glLinkProgram(program);
+
+  return program;
+}
+
+GLuint GLTestHelper::SetupProgram(
+    GLuint vertex_shader, GLuint fragment_shader) {
+  GLuint program = LinkProgram(vertex_shader, fragment_shader);
   // Check the link status
   GLint linked = 0;
   glGetProgramiv(program, GL_LINK_STATUS, &linked);
diff --git a/gpu/command_buffer/tests/gl_test_utils.h b/gpu/command_buffer/tests/gl_test_utils.h
index 15a726e..802d54d 100644
--- a/gpu/command_buffer/tests/gl_test_utils.h
+++ b/gpu/command_buffer/tests/gl_test_utils.h
@@ -18,11 +18,19 @@
   static bool CheckGLError(const char* msg, int line);
 
   // Compiles a shader.
-  // Returns shader, 0 on failure..
+  // Does not check for errors, always returns shader.
+  static GLuint CompileShader(GLenum type, const char* shaderSrc);
+
+  // Compiles a shader and checks for compilation errors.
+  // Returns shader, 0 on failure.
   static GLuint LoadShader(GLenum type, const char* shaderSrc);
 
   // Attaches 2 shaders and links them to a program.
-  // Returns program, 0 on failure..
+  // Does not check for errors, always returns program.
+  static GLuint LinkProgram(GLuint vertex_shader, GLuint fragment_shader);
+
+  // Attaches 2 shaders, links them to a program, and checks for errors.
+  // Returns program, 0 on failure.
   static GLuint SetupProgram(GLuint vertex_shader, GLuint fragment_shader);
 
   // Compiles 2 shaders, attaches and links them to a program
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index 358317c..5cb2a45 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -27,6 +27,8 @@
   'sources': [
     'command_buffer/service/async_pixel_transfer_delegate.cc',
     'command_buffer/service/async_pixel_transfer_delegate.h',
+    'command_buffer/service/async_pixel_transfer_manager.cc',
+    'command_buffer/service/async_pixel_transfer_manager.h',
     'command_buffer/service/async_pixel_transfer_manager_android.cc',
     'command_buffer/service/async_pixel_transfer_manager_idle.cc',
     'command_buffer/service/async_pixel_transfer_manager_idle.h',
@@ -39,10 +41,8 @@
     'command_buffer/service/async_pixel_transfer_manager_sync.cc',
     'command_buffer/service/async_pixel_transfer_manager_sync.h',
     'command_buffer/service/async_pixel_transfer_manager_win.cc',
-    'command_buffer/service/async_pixel_transfer_manager.cc',
-    'command_buffer/service/async_pixel_transfer_manager.h',
-    'command_buffer/service/buffer_manager.h',
     'command_buffer/service/buffer_manager.cc',
+    'command_buffer/service/buffer_manager.h',
     'command_buffer/service/cmd_buffer_engine.h',
     'command_buffer/service/cmd_parser.cc',
     'command_buffer/service/cmd_parser.h',
@@ -50,34 +50,34 @@
     'command_buffer/service/command_buffer_service.h',
     'command_buffer/service/common_decoder.cc',
     'command_buffer/service/common_decoder.h',
-    'command_buffer/service/context_group.h',
     'command_buffer/service/context_group.cc',
+    'command_buffer/service/context_group.h',
+    'command_buffer/service/context_state.cc',
     'command_buffer/service/context_state.h',
     'command_buffer/service/context_state_autogen.h',
     'command_buffer/service/context_state_impl_autogen.h',
-    'command_buffer/service/context_state.cc',
     'command_buffer/service/error_state.cc',
     'command_buffer/service/error_state.h',
-    'command_buffer/service/feature_info.h',
     'command_buffer/service/feature_info.cc',
-    'command_buffer/service/framebuffer_manager.h',
+    'command_buffer/service/feature_info.h',
     'command_buffer/service/framebuffer_manager.cc',
-    'command_buffer/service/gles2_cmd_clear_framebuffer.cc',
-    'command_buffer/service/gles2_cmd_clear_framebuffer.h',
-    'command_buffer/service/gles2_cmd_copy_texture_chromium.cc',
-    'command_buffer/service/gles2_cmd_copy_texture_chromium.h',
-    'command_buffer/service/gles2_cmd_decoder.h',
-    'command_buffer/service/gles2_cmd_decoder_autogen.h',
-    'command_buffer/service/gles2_cmd_decoder.cc',
-    'command_buffer/service/gles2_cmd_validation.h',
-    'command_buffer/service/gles2_cmd_validation.cc',
-    'command_buffer/service/gles2_cmd_validation_autogen.h',
-    'command_buffer/service/gles2_cmd_validation_implementation_autogen.h',
+    'command_buffer/service/framebuffer_manager.h',
     'command_buffer/service/gl_context_virtual.cc',
     'command_buffer/service/gl_context_virtual.h',
     'command_buffer/service/gl_state_restorer_impl.cc',
     'command_buffer/service/gl_state_restorer_impl.h',
     'command_buffer/service/gl_utils.h',
+    'command_buffer/service/gles2_cmd_clear_framebuffer.cc',
+    'command_buffer/service/gles2_cmd_clear_framebuffer.h',
+    'command_buffer/service/gles2_cmd_copy_texture_chromium.cc',
+    'command_buffer/service/gles2_cmd_copy_texture_chromium.h',
+    'command_buffer/service/gles2_cmd_decoder.cc',
+    'command_buffer/service/gles2_cmd_decoder.h',
+    'command_buffer/service/gles2_cmd_decoder_autogen.h',
+    'command_buffer/service/gles2_cmd_validation.cc',
+    'command_buffer/service/gles2_cmd_validation.h',
+    'command_buffer/service/gles2_cmd_validation_autogen.h',
+    'command_buffer/service/gles2_cmd_validation_implementation_autogen.h',
     'command_buffer/service/gpu_scheduler.cc',
     'command_buffer/service/gpu_scheduler.h',
     'command_buffer/service/gpu_scheduler_mock.h',
@@ -85,10 +85,12 @@
     'command_buffer/service/gpu_state_tracer.h',
     'command_buffer/service/gpu_switches.cc',
     'command_buffer/service/gpu_switches.h',
+    'command_buffer/service/gpu_timing.cc',
+    'command_buffer/service/gpu_timing.h',
     'command_buffer/service/gpu_tracer.cc',
     'command_buffer/service/gpu_tracer.h',
-    'command_buffer/service/id_manager.h',
     'command_buffer/service/id_manager.cc',
+    'command_buffer/service/id_manager.h',
     'command_buffer/service/image_factory.cc',
     'command_buffer/service/image_factory.h',
     'command_buffer/service/image_manager.cc',
@@ -102,39 +104,39 @@
     'command_buffer/service/mailbox_manager_impl.h',
     'command_buffer/service/mailbox_manager_sync.cc',
     'command_buffer/service/mailbox_manager_sync.h',
-    'command_buffer/service/memory_program_cache.h',
     'command_buffer/service/memory_program_cache.cc',
+    'command_buffer/service/memory_program_cache.h',
     'command_buffer/service/mocks.h',
-    'command_buffer/service/program_manager.h',
-    'command_buffer/service/program_manager.cc',
-    'command_buffer/service/query_manager.h',
-    'command_buffer/service/query_manager.cc',
-    'command_buffer/service/renderbuffer_manager.h',
-    'command_buffer/service/renderbuffer_manager.cc',
-    'command_buffer/service/program_cache.h',
     'command_buffer/service/program_cache.cc',
-    'command_buffer/service/shader_manager.h',
+    'command_buffer/service/program_cache.h',
+    'command_buffer/service/program_manager.cc',
+    'command_buffer/service/program_manager.h',
+    'command_buffer/service/query_manager.cc',
+    'command_buffer/service/query_manager.h',
+    'command_buffer/service/renderbuffer_manager.cc',
+    'command_buffer/service/renderbuffer_manager.h',
     'command_buffer/service/shader_manager.cc',
-    'command_buffer/service/shader_translator.h',
+    'command_buffer/service/shader_manager.h',
     'command_buffer/service/shader_translator.cc',
-    'command_buffer/service/shader_translator_cache.h',
+    'command_buffer/service/shader_translator.h',
     'command_buffer/service/shader_translator_cache.cc',
-    'command_buffer/service/stream_texture_manager_in_process_android.h',
+    'command_buffer/service/shader_translator_cache.h',
     'command_buffer/service/stream_texture_manager_in_process_android.cc',
-    'command_buffer/service/sync_point_manager.h',
+    'command_buffer/service/stream_texture_manager_in_process_android.h',
     'command_buffer/service/sync_point_manager.cc',
-    'command_buffer/service/texture_definition.h',
+    'command_buffer/service/sync_point_manager.h',
     'command_buffer/service/texture_definition.cc',
-    'command_buffer/service/texture_manager.h',
+    'command_buffer/service/texture_definition.h',
     'command_buffer/service/texture_manager.cc',
+    'command_buffer/service/texture_manager.h',
     '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/valuebuffer_manager.h',
     'command_buffer/service/vertex_array_manager.cc',
-    'command_buffer/service/vertex_attrib_manager.h',
+    'command_buffer/service/vertex_array_manager.h',
     'command_buffer/service/vertex_attrib_manager.cc',
+    'command_buffer/service/vertex_attrib_manager.h',
   ],
   'conditions': [
     ['ui_compositor_image_transport==1', {
diff --git a/gpu/config/BUILD.gn b/gpu/config/BUILD.gn
index be7a444..1d86e69 100644
--- a/gpu/config/BUILD.gn
+++ b/gpu/config/BUILD.gn
@@ -15,17 +15,19 @@
     "dx_diag_node.h",
     "gpu_blacklist.cc",
     "gpu_blacklist.h",
-    "gpu_control_list_jsons.h",
     "gpu_control_list.cc",
     "gpu_control_list.h",
-    "gpu_driver_bug_list_json.cc",
+    "gpu_control_list_jsons.h",
     "gpu_driver_bug_list.cc",
     "gpu_driver_bug_list.h",
+    "gpu_driver_bug_list_json.cc",
     "gpu_driver_bug_workaround_type.h",
     "gpu_dx_diagnostics_win.cc",
     "gpu_feature_type.h",
     "gpu_info.cc",
     "gpu_info.h",
+    "gpu_info_collector.cc",
+    "gpu_info_collector.h",
     "gpu_info_collector_android.cc",
     "gpu_info_collector_linux.cc",
     "gpu_info_collector_linux.h",
@@ -33,8 +35,6 @@
     "gpu_info_collector_ozone.cc",
     "gpu_info_collector_win.cc",
     "gpu_info_collector_x11.cc",
-    "gpu_info_collector.cc",
-    "gpu_info_collector.h",
     "gpu_performance_stats.h",
     "gpu_test_config.cc",
     "gpu_test_config.h",
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index 382bcba..53361eb 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "7.15",
+  "version": "7.16",
   "entries": [
     {
       "id": 1,
@@ -1134,6 +1134,31 @@
       "features": [
         "ignore_egl_sync_failures"
       ]
+    },
+    {
+      "id": 100,
+      "description": "Disable Direct3D11 on systems with AMD switchable graphics",
+      "cr_bugs": [451420],
+      "os": {
+        "type": "win"
+      },
+      "multi_gpu_style": "amd_switchable",
+      "features": [
+        "disable_d3d11"
+      ]
+    },
+    {
+      "id": 101,
+      "description": "The Mali-Txxx driver hangs when reading from currently displayed buffer",
+      "cr_bugs": [457511],
+      "os": {
+        "type": "chromeos"
+      },
+      "gl_vendor": "ARM.*",
+      "gl_renderer": "Mali-T.*",
+      "features": [
+        "disable_post_sub_buffers_for_onscreen_surfaces"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc
index fd1ff8b..521f2cd 100644
--- a/gpu/config/gpu_info_collector.cc
+++ b/gpu/config/gpu_info_collector.cc
@@ -112,6 +112,7 @@
 
   bool supports_robustness =
       gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
+      gpu_info->gl_extensions.find("GL_KHR_robustness") != std::string::npos ||
       gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
   if (supports_robustness) {
     glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index a5686a9..4deee7c 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -407,8 +407,18 @@
                         {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};
 
   // create device info for the display device
-  HDEVINFO device_info =
-      SetupDiGetClassDevsW(&display_class, NULL, NULL, DIGCF_PRESENT);
+  HDEVINFO device_info;
+  if (base::win::GetVersion() <= base::win::VERSION_XP) {
+    // Collection of information on all adapters is much slower on XP (almost
+    // 100ms), and not very useful (as it's not going to use the GPU anyway), so
+    // just collect information on the current device. http://crbug.com/456178
+    device_info =
+        SetupDiGetClassDevsW(NULL, device_id.c_str(), NULL,
+                             DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
+  } else {
+    device_info =
+        SetupDiGetClassDevsW(&display_class, NULL, NULL, DIGCF_PRESENT);
+  }
   if (device_info == INVALID_HANDLE_VALUE) {
     LOG(ERROR) << "Creating device info failed";
     return kCollectInfoNonFatalFailure;
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc
index 228e4c1..bd17250 100644
--- a/gpu/gles2_conform_support/egl/display.cc
+++ b/gpu/gles2_conform_support/egl/display.cc
@@ -335,4 +335,8 @@
   return 0;
 }
 
+void Display::SetLock(base::Lock*) {
+  NOTIMPLEMENTED();
+}
+
 }  // namespace egl
diff --git a/gpu/gles2_conform_support/egl/display.h b/gpu/gles2_conform_support/egl/display.h
index 651ab1a..9b349bd 100644
--- a/gpu/gles2_conform_support/egl/display.h
+++ b/gpu/gles2_conform_support/egl/display.h
@@ -92,6 +92,7 @@
   void SignalQuery(uint32 query, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
   uint32 CreateStreamTexture(uint32 texture_id) override;
+  void SetLock(base::Lock*) override;
 
  private:
   EGLNativeDisplayType display_id_;
diff --git a/gpu/gles2_conform_support/gles2_conform.gypi b/gpu/gles2_conform_support/gles2_conform.gypi
index 41e0f28..6dcf277 100644
--- a/gpu/gles2_conform_support/gles2_conform.gypi
+++ b/gpu/gles2_conform_support/gles2_conform.gypi
@@ -47,12 +47,12 @@
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestPointSizeArray.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestPointSprite.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestPointSprite.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRGB8RGBA8.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRGB8RGBA8.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestReadFormat.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestReadFormat.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRequiredInternalformat.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRequiredInternalformat.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRGB8RGBA8.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRGB8RGBA8.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil1.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil1.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil4.c',
@@ -200,34 +200,40 @@
     'gtf_es_sources': [
       # Bootstrapping files commented out. We have different bootstrapping
       # files for each platform.
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/egl_config_select.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/egl_config_select.h',
-      #'<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglu.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglu.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglut.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglut.h',
       # Note: FilesDATA.h, FilesDATA.c, and FilesTOC.c are generated
       # by GTF_ES/glsl/GTF/mergeTestFilesToCSource.pl
-      '<(SHARED_INTERMEDIATE_DIR)/gles2_conform_test_embedded_data/FilesDATA.c',
-      '<(SHARED_INTERMEDIATE_DIR)/gles2_conform_test_embedded_data/FilesDATA.h',
-      '<(SHARED_INTERMEDIATE_DIR)/gles2_conform_test_embedded_data/FilesTOC.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/FilesTOC.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/gl2ext_missing.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/gl2Native.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/gl2Native.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFAttDataGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFAttDataGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFDepthRangeParamGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFDepthRangeParamGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFModelDataGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFModelDataGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFPointParamGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFPointParamGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFReadPixelsGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFReadPixelsGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFShaderDataGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFShaderDataGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFShaderTextGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFShaderTextGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFStateDataGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFStateDataGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFTexDataGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFTexDataGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFTexParamGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFTexParamGL.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFUniDataGL.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFUniDataGL.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFArguments.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFArguments.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFCoverageDict.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFCoverageGL.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFCoverageGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFCoverageDict.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFDict.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFDictBase.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFFileReader.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFFileReader.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFgl.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFgl.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFInitEGL.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFLog.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFLog.h',
@@ -273,34 +279,28 @@
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFVecBase.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFVector.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFVersion.h',
-      #'<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/main.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFgl.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFgl.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/MIMG.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/MIMG.h',
       #'<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/Win32Console.h',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/XmlUtils.c',
       '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/XmlUtils.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFAttDataGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFAttDataGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFDepthRangeParamGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFDepthRangeParamGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFModelDataGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFModelDataGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFPointParamGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFPointParamGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFReadPixelsGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFReadPixelsGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFShaderDataGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFShaderDataGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFShaderTextGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFShaderTextGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFStateDataGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFStateDataGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFTexDataGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFTexDataGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFTexParamGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFTexParamGL.h',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFUniDataGL.c',
-      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GL/GTFUniDataGL.h',
+      #'<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/egl_config_select.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/egl_config_select.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglu.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglu.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglut.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglut.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/gl2Native.c',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/gl2Native.h',
+      '<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/gl2ext_missing.h',
+      #'<(DEPTH)/third_party/gles2_conform/GTF_ES/glsl/GTF/Source/main.c',
+      '<(SHARED_INTERMEDIATE_DIR)/gles2_conform_test_embedded_data/FilesDATA.c',
+      '<(SHARED_INTERMEDIATE_DIR)/gles2_conform_test_embedded_data/FilesDATA.h',
+      '<(SHARED_INTERMEDIATE_DIR)/gles2_conform_test_embedded_data/FilesTOC.c',
       '<@(gl2_extension_test_sources)',
       '<@(gl2_fixed_test_sources)',
       '<@(gl2_test_sources)',
diff --git a/gpu/gles2_conform_support/gles2_conform_support.gyp b/gpu/gles2_conform_support/gles2_conform_support.gyp
index 928b152..6bf8510 100644
--- a/gpu/gles2_conform_support/gles2_conform_support.gyp
+++ b/gpu/gles2_conform_support/gles2_conform_support.gyp
@@ -14,8 +14,8 @@
    'conditions': [
      ['OS=="linux"', {
        'bootstrap_sources_native': [
-         'native/egl_native_aura.cc',
          'native/egl_native.cc',
+         'native/egl_native_aura.cc',
          'native/egl_native_x11.cc',
        ],
      }],
@@ -84,9 +84,9 @@
         '../../third_party/khronos/khronos.gyp:khronos_headers',
       ],
       'sources': [
-        'native/main.cc',
         'native/egl_native.cc',
         'native/egl_native_windowless.cc',
+        'native/main.cc',
         '<@(bootstrap_sources_native)',
       ],
       'defines': [
diff --git a/gpu/gles2_conform_support/gles2_conform_test.gyp b/gpu/gles2_conform_support/gles2_conform_test.gyp
index 4cbb35b..1f23efa 100644
--- a/gpu/gles2_conform_support/gles2_conform_test.gyp
+++ b/gpu/gles2_conform_support/gles2_conform_test.gyp
@@ -137,12 +137,9 @@
                 4018,  # signed/unsigned mismatch
                 4101,  # unreferenced local variable
                 4715,  # not all control paths return a value
+                4267,  # size_t/unsigned int conversion
               ],
-              'msvs_settings': {
-                'VCCLCompilerTool': {
-                  'AdditionalOptions': ['/UNOMINMAX'],
-                },
-              },
+              'defines!': [ 'NOMINMAX' ],
             }],
             ['OS=="mac"', {
               'defines': [
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 73a1059..70e99c8 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -54,8 +54,8 @@
         'GL_IN_PROCESS_CONTEXT_IMPLEMENTATION',
       ],
       'sources': [
-        'command_buffer/client/gl_in_process_context.h',
         'command_buffer/client/gl_in_process_context.cc',
+        'command_buffer/client/gl_in_process_context.h',
         'command_buffer/client/gl_in_process_context_export.h',
       ],
     },
@@ -194,10 +194,10 @@
         'command_buffer/common/id_allocator_test.cc',
         'command_buffer/common/trace_event.h',
         'command_buffer/common/unittest_main.cc',
-        'command_buffer/service/async_pixel_transfer_delegate_mock.h',
         'command_buffer/service/async_pixel_transfer_delegate_mock.cc',
-        'command_buffer/service/async_pixel_transfer_manager_mock.h',
+        'command_buffer/service/async_pixel_transfer_delegate_mock.h',
         'command_buffer/service/async_pixel_transfer_manager_mock.cc',
+        'command_buffer/service/async_pixel_transfer_manager_mock.h',
         'command_buffer/service/buffer_manager_unittest.cc',
         'command_buffer/service/cmd_parser_test.cc',
         'command_buffer/service/command_buffer_service_unittest.cc',
@@ -205,6 +205,8 @@
         'command_buffer/service/context_group_unittest.cc',
         'command_buffer/service/feature_info_unittest.cc',
         'command_buffer/service/framebuffer_manager_unittest.cc',
+        'command_buffer/service/gl_surface_mock.cc',
+        'command_buffer/service/gl_surface_mock.h',
         'command_buffer/service/gles2_cmd_decoder_unittest.cc',
         'command_buffer/service/gles2_cmd_decoder_unittest.h',
         'command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h',
@@ -215,6 +217,7 @@
         'command_buffer/service/gles2_cmd_decoder_unittest_3.cc',
         'command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h',
         'command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc',
+        'command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc',
         'command_buffer/service/gles2_cmd_decoder_unittest_base.cc',
         'command_buffer/service/gles2_cmd_decoder_unittest_base.h',
         'command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc',
@@ -224,33 +227,30 @@
         'command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc',
         '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',
         'command_buffer/service/gpu_service_test.cc',
         'command_buffer/service/gpu_service_test.h',
+        'command_buffer/service/gpu_tracer_unittest.cc',
         'command_buffer/service/id_manager_unittest.cc',
         'command_buffer/service/mailbox_manager_unittest.cc',
         'command_buffer/service/memory_program_cache_unittest.cc',
         'command_buffer/service/mocks.cc',
         'command_buffer/service/mocks.h',
+        'command_buffer/service/program_cache_unittest.cc',
         'command_buffer/service/program_manager_unittest.cc',
         'command_buffer/service/query_manager_unittest.cc',
         'command_buffer/service/renderbuffer_manager_unittest.cc',
-        'command_buffer/service/program_cache_unittest.cc',
         'command_buffer/service/shader_manager_unittest.cc',
-        'command_buffer/service/shader_translator_unittest.cc',
         'command_buffer/service/shader_translator_cache_unittest.cc',
+        'command_buffer/service/shader_translator_unittest.cc',
         'command_buffer/service/test_helper.cc',
         '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',
+        'command_buffer/service/vertex_attrib_manager_unittest.cc',
         'config/gpu_blacklist_unittest.cc',
         'config/gpu_control_list_entry_unittest.cc',
         'config/gpu_control_list_number_info_unittest.cc',
@@ -291,8 +291,10 @@
         '../testing/perf/perf_test.gyp:perf_test',
         '../ui/gfx/gfx.gyp:gfx_geometry',
         '../ui/gl/gl.gyp:gl',
+        'command_buffer_service',
       ],
       'sources': [
+        'perftests/measurements.cc',
         'perftests/run_all_tests.cc',
         'perftests/texture_upload_perftest.cc',
       ],
@@ -386,10 +388,10 @@
         '..',
       ],
       'sources': [
-        'command_buffer/service/gles2_cmd_decoder_mock.cc',
-        'command_buffer/service/error_state_mock.cc',
         'command_buffer/client/gles2_interface_stub.cc',
         'command_buffer/client/gles2_interface_stub.h',
+        'command_buffer/service/error_state_mock.cc',
+        'command_buffer/service/gles2_cmd_decoder_mock.cc',
       ],
     },
   ],
diff --git a/gpu/gpu_common.gypi b/gpu/gpu_common.gypi
index 5ff16da..b66d5ea 100644
--- a/gpu/gpu_common.gypi
+++ b/gpu/gpu_common.gypi
@@ -12,8 +12,8 @@
       'command_buffer/client/gles2_c_lib.cc',
       'command_buffer/client/gles2_c_lib_autogen.h',
       'command_buffer/client/gles2_c_lib_export.h',
-      'command_buffer/client/gles2_lib.h',
       'command_buffer/client/gles2_lib.cc',
+      'command_buffer/client/gles2_lib.h',
     ],
     # These are defined here because we need to build this library twice. Once
     # with without support for client side arrays and once with for pepper and
@@ -21,19 +21,19 @@
     'gles2_implementation_source_files': [
       'command_buffer/client/buffer_tracker.cc',
       'command_buffer/client/buffer_tracker.h',
-      'command_buffer/client/client_context_state.h',
       'command_buffer/client/client_context_state.cc',
+      'command_buffer/client/client_context_state.h',
       'command_buffer/client/client_context_state_autogen.h',
       'command_buffer/client/client_context_state_impl_autogen.h',
       'command_buffer/client/gles2_impl_export.h',
-      'command_buffer/client/gles2_implementation_autogen.h',
       'command_buffer/client/gles2_implementation.cc',
       'command_buffer/client/gles2_implementation.h',
+      'command_buffer/client/gles2_implementation_autogen.h',
       'command_buffer/client/gles2_implementation_impl_autogen.h',
       'command_buffer/client/gles2_interface.h',
-      'command_buffer/client/gles2_trace_implementation_autogen.h',
       'command_buffer/client/gles2_trace_implementation.cc',
       'command_buffer/client/gles2_trace_implementation.h',
+      'command_buffer/client/gles2_trace_implementation_autogen.h',
       'command_buffer/client/gles2_trace_implementation_impl_autogen.h',
       'command_buffer/client/gpu_switches.cc',
       'command_buffer/client/gpu_switches.h',
diff --git a/gpu/gpu_config.gypi b/gpu/gpu_config.gypi
index 98b19aa..f1915f3 100644
--- a/gpu/gpu_config.gypi
+++ b/gpu/gpu_config.gypi
@@ -16,17 +16,19 @@
     'config/dx_diag_node.h',
     'config/gpu_blacklist.cc',
     'config/gpu_blacklist.h',
-    'config/gpu_control_list_jsons.h',
     'config/gpu_control_list.cc',
     'config/gpu_control_list.h',
-    'config/gpu_driver_bug_list_json.cc',
+    'config/gpu_control_list_jsons.h',
     'config/gpu_driver_bug_list.cc',
     'config/gpu_driver_bug_list.h',
+    'config/gpu_driver_bug_list_json.cc',
     'config/gpu_driver_bug_workaround_type.h',
     'config/gpu_dx_diagnostics_win.cc',
     'config/gpu_feature_type.h',
     'config/gpu_info.cc',
     'config/gpu_info.h',
+    'config/gpu_info_collector.cc',
+    'config/gpu_info_collector.h',
     'config/gpu_info_collector_android.cc',
     'config/gpu_info_collector_linux.cc',
     'config/gpu_info_collector_linux.h',
@@ -34,8 +36,6 @@
     'config/gpu_info_collector_ozone.cc',
     'config/gpu_info_collector_win.cc',
     'config/gpu_info_collector_x11.cc',
-    'config/gpu_info_collector.cc',
-    'config/gpu_info_collector.h',
     'config/gpu_performance_stats.h',
     'config/gpu_test_config.cc',
     'config/gpu_test_config.h',
diff --git a/gpu/gpu_unittests.isolate b/gpu/gpu_unittests.isolate
index 48fb1c5..e64633c 100644
--- a/gpu/gpu_unittests.isolate
+++ b/gpu/gpu_unittests.isolate
@@ -58,6 +58,13 @@
         ],
       },
     }],
+    ['OS=="mac" and asan==1 and fastbuild==0', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/gpu_unittests.dSYM/',
+        ],
+      },
+    }],
     ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
       'variables': {
         'files': [
diff --git a/gpu/khronos_glcts_support/khronos_glcts.gypi b/gpu/khronos_glcts_support/khronos_glcts.gypi
index ebd8919..07d9cd1 100644
--- a/gpu/khronos_glcts_support/khronos_glcts.gypi
+++ b/gpu/khronos_glcts_support/khronos_glcts.gypi
@@ -53,23 +53,23 @@
     ],
     'gtf_core_srcs': [
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFArguments.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTest.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestDriver.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/MIMG.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFFileReader.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFLog.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/XmlUtils.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFMemFile.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFModelData.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFPort.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFStringUtils.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTest.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestCompareGL.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestDriver.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestElement.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestUtil.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFgl.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/MIMG.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/XmlUtils.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/eglu.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/eglut.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/gl2Native.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFgl.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFPort.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFModelData.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFStringUtils.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestElement.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFFileReader.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestUtil.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestCompareGL.c',
     ],
     'gtf_gl_core_srcs': [
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFAttDataGL.c',
@@ -80,19 +80,18 @@
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFShaderDataGL.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFShaderTextGL.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFStateDataGL.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFTestTextureFloatBase.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFTexDataGL.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFTexParamGL.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFUniDataGL.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL/GTFTestTextureFloatBase.c',
     ],
     'gtf_gles2_srcs': [
       # Base
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestGL2Test.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestAttributeGL.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestDetachGL.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestCreateObjectGL.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestUniformQueryGL.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestBindAllAttributes.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestCreateObjectGL.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestDetachGL.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestFixedDataType.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestFramebufferObjects.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestGetAttachedObjects.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestGetAttributeLocation.c',
@@ -108,10 +107,11 @@
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestMultipleShaders.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestRelinkProgram.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestUniform.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestUniformQueryGL.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestVertexAttribPointer.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestVertexAttributes.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestVertexProgramPointSize.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2Tests/GTFGL2TestFixedDataType.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestGL2Test.c',
 
       # Build
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestBuildGL.c',
@@ -127,11 +127,10 @@
 
       # Coverage
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFCoverageDict.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestCoverageGL.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFCoverageGL.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestCoverageGL.c',
 
       # Fixed-function
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestFixedGL.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestBlend.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestBufferClear.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestBufferColor.c',
@@ -143,7 +142,6 @@
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestDepthBufferClear.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestDepthBufferFunctions.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestDither.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestUserClipPlanes.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestDivideByZero.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestGets.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestMipmapsInterpolation.c',
@@ -160,51 +158,53 @@
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestTransformViewport.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestTriangleRasterization.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestTriangleTiling.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestUserClipPlanes.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestVertexOrder.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedTestViewportClamp.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedUtilg.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2FixedTests/GTFFixedUtilr.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestFixedGL.c',
 
       # Extensions
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestExtension.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestFramebufferObject.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil8.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestConditionalQuery.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestDataType1010102.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestDebug.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestDepth24.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestDepth32.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestDepthTexture.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestDepthTextureCubeMap.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestElementIndexUINT.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestFBORenderMipmap.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestFragmentPrecisionHigh.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestFramebufferObject.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestMapBuffer.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestOcclusionQuery.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestPackedDepthStencil.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestPointSizeArray.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestPointSprite.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestReadFormat.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil1.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil4.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil8.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestTexture3D.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestTextureCompressionASTCLDR.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestTextureFloat.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestTextureFloatLinear.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestTextureNPOT.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestUtilp.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestOcclusionQuery.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestConditionalQuery.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestPackedDepthStencil.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestVertexArrayObject.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestTextureCompressionASTCLDR.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestDepthTextureCubeMap.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil1.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestStencil4.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestVertexHalfFloat.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestReadFormat.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GTFTestExtension.c',
     ],
     'gtf_gles2_es_only_srcs': [
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestCompressedPalettedTexture.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestCompressedETC1RGB8Texture.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRGB8RGBA8.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestEGLImage.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestSurfacelessContext.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestEGLImageExternal.c',
-      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRequiredInternalformat.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestCompressedPalettedTexture.c',
       '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestEGLCreateContext.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestEGLImage.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestEGLImageExternal.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRGB8RGBA8.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestRequiredInternalformat.c',
+      '<(DEPTH)/third_party/khronos_glcts/GTF_ES/glsl/GTF/Source/GL2ExtensionTests/GTFExtensionTestSurfacelessContext.c',
     ],
     'glcts_common_sources': [
       '<(DEPTH)/third_party/khronos_glcts/cts/common/glcConfigList.cpp',
@@ -425,10 +425,10 @@
       '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/deMemPool.h',
       '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolArray.c',
       '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolArray.h',
-      '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHashArray.c',
-      '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHashArray.h',
       '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHash.c',
       '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHash.h',
+      '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHashArray.c',
+      '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHashArray.h',
       '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHashSet.c',
       '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHashSet.h',
       '<(DEPTH)/third_party/khronos_glcts/framework/delibs/depool/dePoolHeap.c',
diff --git a/gpu/perftests/measurements.cc b/gpu/perftests/measurements.cc
new file mode 100644
index 0000000..270e459
--- /dev/null
+++ b/gpu/perftests/measurements.cc
@@ -0,0 +1,99 @@
+// Copyright 2015 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/perftests/measurements.h"
+
+#include "testing/perf/perf_test.h"
+
+namespace gpu {
+
+Measurement::Measurement() : name(), wall_time(), cpu_time(), gpu_time() {
+}
+Measurement::Measurement(const Measurement& m)
+    : name(m.name),
+      wall_time(m.wall_time),
+      cpu_time(m.cpu_time),
+      gpu_time(m.gpu_time) {
+}
+Measurement::Measurement(const std::string& name,
+                         const base::TimeDelta wall_time,
+                         const base::TimeDelta cpu_time,
+                         const base::TimeDelta gpu_time)
+    : name(name), wall_time(wall_time), cpu_time(cpu_time), gpu_time(gpu_time) {
+}
+
+void Measurement::PrintResult() const {
+  perf_test::PrintResult(name, "_wall", "", wall_time.InMillisecondsF(), "ms",
+                         true);
+  if (cpu_time.InMicroseconds() >= 0) {
+    perf_test::PrintResult(name, "_cpu", "", cpu_time.InMillisecondsF(), "ms",
+                           true);
+  }
+  if (gpu_time.InMicroseconds() >= 0) {
+    perf_test::PrintResult(name, "_gpu", "", gpu_time.InMillisecondsF(), "ms",
+                           true);
+  }
+}
+
+Measurement& Measurement::Increment(const Measurement& m) {
+  wall_time += m.wall_time;
+  cpu_time += m.cpu_time;
+  gpu_time += m.gpu_time;
+  return *this;
+}
+
+Measurement Measurement::Divide(int a) const {
+  return Measurement(name, wall_time / a, cpu_time / a, gpu_time / a);
+}
+
+Measurement::~Measurement() {
+}
+
+MeasurementTimers::MeasurementTimers(GPUTiming* gpu_timing)
+    : wall_time_start_(), cpu_time_start_(), gpu_timer_() {
+  DCHECK(gpu_timing);
+  wall_time_start_ = base::TimeTicks::NowFromSystemTraceTime();
+  if (base::TimeTicks::IsThreadNowSupported()) {
+    cpu_time_start_ = base::TimeTicks::ThreadNow();
+  } else {
+    static bool logged_once = false;
+    LOG_IF(WARNING, !logged_once) << "ThreadNow not supported.";
+    logged_once = true;
+  }
+
+  if (gpu_timing->IsAvailable()) {
+    gpu_timer_.reset(new GPUTimer(gpu_timing));
+    gpu_timer_->Start();
+  }
+}
+
+void MeasurementTimers::Record() {
+  wall_time_ = base::TimeTicks::NowFromSystemTraceTime() - wall_time_start_;
+  if (base::TimeTicks::IsThreadNowSupported()) {
+    cpu_time_ = base::TimeTicks::ThreadNow() - cpu_time_start_;
+  }
+  if (gpu_timer_.get()) {
+    gpu_timer_->End();
+  }
+}
+
+Measurement MeasurementTimers::GetAsMeasurement(const std::string& name) {
+  DCHECK_NE(base::TimeDelta(),
+            wall_time_);  // At least wall_time_ has been set.
+
+  if (!base::TimeTicks::IsThreadNowSupported()) {
+    cpu_time_ = base::TimeDelta::FromMicroseconds(-1);
+  }
+  int64 gpu_time = -1;
+  if (gpu_timer_.get() != nullptr && gpu_timer_->IsAvailable()) {
+    gpu_time = gpu_timer_->GetDeltaElapsed();
+  }
+  return Measurement(name, wall_time_, cpu_time_,
+                     base::TimeDelta::FromMicroseconds(gpu_time));
+}
+
+MeasurementTimers::~MeasurementTimers() {
+}
+
+}  // namespace gpu
diff --git a/gpu/perftests/measurements.h b/gpu/perftests/measurements.h
new file mode 100644
index 0000000..15be422
--- /dev/null
+++ b/gpu/perftests/measurements.h
@@ -0,0 +1,56 @@
+// Copyright 2015 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_PERFTESTS_MEASUREMENTS_H_
+#define GPU_PERFTESTS_MEASUREMENTS_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "gpu/command_buffer/service/gpu_timing.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace gpu {
+struct Measurement {
+  Measurement();
+  Measurement(const Measurement& m);
+  Measurement(const std::string& name,
+              const base::TimeDelta wall_time,
+              const base::TimeDelta cpu_time,
+              const base::TimeDelta gpu_time);
+  ~Measurement();
+
+  void PrintResult() const;
+  Measurement& Increment(const Measurement& m);
+  Measurement Divide(int a) const;
+
+  std::string name;
+  base::TimeDelta wall_time;
+  base::TimeDelta cpu_time;
+  base::TimeDelta gpu_time;
+};
+
+// Class to measure wall, cpu and gpu time deltas.
+// The deltas are measured from the time of the object
+// creation up to when Record is called.
+class MeasurementTimers {
+ public:
+  explicit MeasurementTimers(GPUTiming* gpu_timing);
+  void Record();
+  Measurement GetAsMeasurement(const std::string& name);
+  ~MeasurementTimers();
+
+ private:
+  base::TimeTicks wall_time_start_;
+  base::TimeTicks cpu_time_start_;
+  scoped_ptr<gpu::GPUTimer> gpu_timer_;
+
+  base::TimeDelta wall_time_;
+  base::TimeDelta cpu_time_;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_PERFTESTS_MEASUREMENTS_H_
diff --git a/gpu/perftests/texture_upload_perftest.cc b/gpu/perftests/texture_upload_perftest.cc
index 7166c2a..f691c9e 100644
--- a/gpu/perftests/texture_upload_perftest.cc
+++ b/gpu/perftests/texture_upload_perftest.cc
@@ -8,10 +8,8 @@
 #include "base/containers/small_map.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
-#include "base/timer/elapsed_timer.h"
+#include "gpu/perftests/measurements.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
@@ -103,9 +101,18 @@
                                                   surface_.get(),
                                                   gfx::PreferIntegratedGpu);
 
+    ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get());
+    if (gpu_timing_.Initialize(gl_context_.get())) {
+      LOG(INFO) << "Gpu timing initialized with timer type: "
+                << gpu_timing_.GetTimerTypeName();
+      gpu_timing_.CheckAndResetTimerErrors();
+      gpu_timing_.InvalidateTimerOffset();
+    } else {
+      LOG(WARNING) << "Can't initialize gpu timing";
+    }
+
     // Prepare a simple program and a vertex buffer that will be
     // used to draw a quad on the offscreen surface.
-    ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get());
     vertex_shader_ = LoadShader(GL_VERTEX_SHADER, kVertexShader);
     fragment_shader_ = LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
     program_object_ = glCreateProgram();
@@ -153,26 +160,18 @@
   }
 
  protected:
-  struct Measurement {
-    Measurement() : name(), wall_time(){};
-    Measurement(const std::string& name, const base::TimeDelta wall_time)
-        : name(name), wall_time(wall_time){};
-    std::string name;
-    base::TimeDelta wall_time;
-  };
   // Upload and draw on the offscren surface.
   // Return a list of pair. Each pair describe a gl operation and the wall
   // time elapsed in milliseconds.
   std::vector<Measurement> UploadAndDraw(const std::vector<uint8>& pixels,
                                          const GLenum format,
                                          const GLenum type) {
-    std::vector<Measurement> measurements;
     ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get());
 
-    base::ElapsedTimer total_timer;
+    MeasurementTimers total_timers(&gpu_timing_);
     GLuint texture_id = 0;
 
-    base::ElapsedTimer tex_timer;
+    MeasurementTimers tex_timers(&gpu_timing_);
     glActiveTexture(GL_TEXTURE0);
     glGenTextures(1, &texture_id);
     glBindTexture(GL_TEXTURE_2D, texture_id);
@@ -184,9 +183,9 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     CheckNoGlError();
-    measurements.push_back(Measurement("teximage2d", tex_timer.Elapsed()));
+    tex_timers.Record();
 
-    base::ElapsedTimer draw_timer;
+    MeasurementTimers draw_timers(&gpu_timing_);
     glUseProgram(program_object_);
     glUniform1i(sampler_location_, 0);
 
@@ -195,13 +194,13 @@
     glEnableVertexAttribArray(0);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-    measurements.push_back(Measurement("drawarrays", draw_timer.Elapsed()));
+    draw_timers.Record();
 
-    base::ElapsedTimer finish_timer;
+    MeasurementTimers finish_timers(&gpu_timing_);
     glFinish();
     CheckNoGlError();
-    measurements.push_back(Measurement("finish", finish_timer.Elapsed()));
-    measurements.push_back(Measurement("total", total_timer.Elapsed()));
+    finish_timers.Record();
+    total_timers.Record();
 
     glDeleteTextures(1, &texture_id);
 
@@ -214,12 +213,19 @@
     // the appropriate format conversion.
     EXPECT_EQ(static_cast<GLenum>(GL_RGBA), format);
     EXPECT_EQ(pixels, pixels_rendered);
+
+    std::vector<Measurement> measurements;
+    measurements.push_back(total_timers.GetAsMeasurement("total"));
+    measurements.push_back(tex_timers.GetAsMeasurement("teximage2d"));
+    measurements.push_back(draw_timers.GetAsMeasurement("drawarrays"));
+    measurements.push_back(finish_timers.GetAsMeasurement("finish"));
     return measurements;
   }
 
   const gfx::Size size_;  // for the offscreen surface and the texture
   scoped_refptr<gfx::GLContext> gl_context_;
   scoped_refptr<gfx::GLSurface> surface_;
+  GPUTiming gpu_timing_;
 
   GLuint vertex_shader_ = 0;
   GLuint fragment_shader_ = 0;
@@ -241,16 +247,14 @@
       for (const Measurement& m : run) {
         auto& agg = aggregates[m.name];
         agg.name = m.name;
-        agg.wall_time += m.wall_time;
+        agg.Increment(m);
       }
     }
   }
 
   for (const auto& entry : aggregates) {
-    const auto& m = entry.second;
-    perf_test::PrintResult(
-        m.name, "", "", (m.wall_time / kUploadPerfTestRuns).InMillisecondsF(),
-        "ms", true);
+    const auto m = entry.second.Divide(kUploadPerfTestRuns);
+    m.PrintResult();
   }
 }
 
diff --git a/gpu/tools/tools.gyp b/gpu/tools/tools.gyp
index f659d72..73ef754 100644
--- a/gpu/tools/tools.gyp
+++ b/gpu/tools/tools.gyp
@@ -25,11 +25,11 @@
           ],
           'sources': [
             'compositor_model_bench/compositor_model_bench.cc',
+            'compositor_model_bench/forward_render_model.cc',
+            'compositor_model_bench/render_model_utils.cc',
+            'compositor_model_bench/render_models.cc',
             'compositor_model_bench/render_tree.cc',
             'compositor_model_bench/shaders.cc',
-            'compositor_model_bench/render_models.cc',
-            'compositor_model_bench/render_model_utils.cc',
-            'compositor_model_bench/forward_render_model.cc',
           ],
         },
       ],