Various fixes for the OpenGL ES 2.0 conformance tests.

Was failing 268 of 1198
Now failing 266 of 1198

ugh! all those changes only fixed 2 tests :-(

TEST=some unit test and conformance tests.
BUG=none

Review URL: http://codereview.chromium.org/1942004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46572 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 6b2efad..8e7867c 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -809,12 +809,10 @@
   // Compute the total size.
   uint32 total_size = 1;
   for (GLsizei ii = 0; ii < count; ++ii) {
-    // I shouldn't have to check for this. The spec doesn't allow this
-    if (!source[ii]) {
-      SetGLError(GL_INVALID_VALUE, "glShaderSource: null passed for string.");
-      return;
+    if (source[ii]) {
+      total_size +=
+          (length && length[ii] >= 0) ? length[ii] : strlen(source[ii]);
     }
-    total_size += (length && length[ii] >= 0) ? length[ii] : strlen(source[ii]);
   }
 
   // Concatenate all the strings in to a bucket on the service.
@@ -823,19 +821,20 @@
   uint32 offset = 0;
   for (GLsizei ii = 0; ii <= count; ++ii) {
     const char* src = ii < count ? source[ii] : "";
-
-    uint32 size = ii < count ? (length ? length[ii] : strlen(src)) : 1;
-    while (size) {
-      uint32 part_size = std::min(size, max_size);
-      void* buffer = transfer_buffer_.Alloc(part_size);
-      memcpy(buffer, src, part_size);
-      helper_->SetBucketData(kResultBucketId, offset, part_size,
-                             transfer_buffer_id_,
-                             transfer_buffer_.GetOffset(buffer));
-      transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
-      offset += part_size;
-      src += part_size;
-      size -= part_size;
+    if (src) {
+      uint32 size = ii < count ? (length ? length[ii] : strlen(src)) : 1;
+      while (size) {
+        uint32 part_size = std::min(size, max_size);
+        void* buffer = transfer_buffer_.Alloc(part_size);
+        memcpy(buffer, src, part_size);
+        helper_->SetBucketData(kResultBucketId, offset, part_size,
+                               transfer_buffer_id_,
+                               transfer_buffer_.GetOffset(buffer));
+        transfer_buffer_.FreePendingToken(buffer, helper_->InsertToken());
+        offset += part_size;
+        src += part_size;
+        size -= part_size;
+      }
     }
   }
 
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index e43bf84..b73b889 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -626,6 +626,8 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+#endif  // defined(GLES2_SUPPORT_CLIENT_SIDE_BUFFERS)
+
 TEST_F(GLES2ImplementationTest, ReservedIds) {
   // Only the get error command should be issued.
   struct Cmds {
@@ -650,8 +652,42 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
-#endif  // defined(GLES2_SUPPORT_CLIENT_SIDE_BUFFERS)
+TEST_F(GLES2ImplementationTest, ReadPixels2Reads) {
+  struct Cmds {
+    ReadPixels read1;
+    cmd::SetToken set_token1;
+    ReadPixels read2;
+    cmd::SetToken set_token2;
+  };
+  const GLint kBytesPerPixel = 4;
+  const GLint kWidth =
+      (kTransferBufferSize - GLES2Implementation::kStartingOffset) /
+      kBytesPerPixel;
+  const GLint kHeight = 2;
+  const GLenum kFormat = GL_RGBA;
+  const GLenum kType = GL_UNSIGNED_BYTE;
 
+  int32 token = 1;
+  uint32 offset = GLES2Implementation::kStartingOffset;
+  Cmds expected;
+  expected.read1.Init(0, 0, kWidth, kHeight / 2, kFormat, kType,
+                      kTransferBufferId, offset,
+                      kTransferBufferId, 0);
+  expected.set_token1.Init(token++);
+  expected.read2.Init(0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType,
+                      kTransferBufferId, offset,
+                      kTransferBufferId, 0);
+  expected.set_token2.Init(token++);
+  scoped_array<int8> buffer(new int8[kWidth * kHeight * kBytesPerPixel]);
+
+  EXPECT_CALL(*command_buffer_, OnFlush(_))
+      .WillOnce(SetMemory(uint32(1)))
+      .WillOnce(SetMemory(uint32(1)))
+      .RetiresOnSaturation();
+
+  gl_->ReadPixels(0, 0, kWidth, kHeight, kFormat, kType, buffer.get());
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
 
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc
index dbc382c..ab5ab8ac 100644
--- a/gpu/command_buffer/service/buffer_manager.cc
+++ b/gpu/command_buffer/service/buffer_manager.cc
@@ -124,6 +124,18 @@
   return true;
 }
 
+bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const {
+  // This doesn't need to be fast. It's only used during slow queries.
+  for (BufferInfoMap::const_iterator it = buffer_infos_.begin();
+       it != buffer_infos_.end(); ++it) {
+    if (it->second->service_id() == service_id) {
+      *client_id = it->first;
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/service/buffer_manager.h b/gpu/command_buffer/service/buffer_manager.h
index 7eefd521..d944532 100644
--- a/gpu/command_buffer/service/buffer_manager.h
+++ b/gpu/command_buffer/service/buffer_manager.h
@@ -142,6 +142,9 @@
   // Removes a buffer info for the given buffer.
   void RemoveBufferInfo(GLuint client_id);
 
+  // Gets a client id for a given service id.
+  bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
  private:
   // Info for each buffer in the system.
   // TODO(gman): Choose a faster container.
diff --git a/gpu/command_buffer/service/buffer_manager_unittest.cc b/gpu/command_buffer/service/buffer_manager_unittest.cc
index 2346f7cc..83a33fd 100644
--- a/gpu/command_buffer/service/buffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/buffer_manager_unittest.cc
@@ -37,6 +37,9 @@
   EXPECT_EQ(0, info1->size());
   EXPECT_FALSE(info1->IsDeleted());
   EXPECT_EQ(kServiceBuffer1Id, info1->service_id());
+  GLuint client_id = 0;
+  EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id));
+  EXPECT_EQ(kClientBuffer1Id, client_id);
   info1->set_target(GL_ELEMENT_ARRAY_BUFFER);
   EXPECT_EQ(static_cast<GLenum>(GL_ELEMENT_ARRAY_BUFFER), info1->target());
   // Check we and set its size.
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc
index fb1014ad..1a7d739 100644
--- a/gpu/command_buffer/service/framebuffer_manager.cc
+++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -46,6 +46,19 @@
   }
 }
 
+bool FramebufferManager::GetClientId(
+    GLuint service_id, GLuint* client_id) const {
+  // This doesn't need to be fast. It's only used during slow queries.
+  for (FramebufferInfoMap::const_iterator it = framebuffer_infos_.begin();
+       it != framebuffer_infos_.end(); ++it) {
+    if (it->second->service_id() == service_id) {
+      *client_id = it->first;
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index db05c5b..3ecb54b 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -73,6 +73,9 @@
   // Removes a framebuffer info for the given framebuffer.
   void RemoveFramebufferInfo(GLuint client_id);
 
+  // Gets a client id for a given service id.
+  bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
  private:
   // Info for each framebuffer in the system.
   // TODO(gman): Choose a faster container.
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
index 1c57c852..75d0da6 100644
--- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -35,6 +35,9 @@
   ASSERT_TRUE(info1 != NULL);
   EXPECT_FALSE(info1->IsDeleted());
   EXPECT_EQ(kService1Id, info1->service_id());
+  GLuint client_id = 0;
+  EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id));
+  EXPECT_EQ(kClient1Id, client_id);
   // Check we get nothing for a non-existent framebuffer.
   EXPECT_TRUE(manager_.GetFramebufferInfo(kClient2Id) == NULL);
   // Check trying to a remove non-existent framebuffers does not crash.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 988bc18..93f28f9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -506,6 +506,25 @@
     return (info && !info->IsDeleted()) ? info : NULL;
   }
 
+  // Gets the program info for the given program. If it's not a program
+  // generates a GL error. Returns NULL if not program.
+  ProgramManager::ProgramInfo* GetProgramInfoNotShader(
+      GLuint client_id, const char* function_name) {
+    ProgramManager::ProgramInfo* info = GetProgramInfo(client_id);
+    if (!info) {
+      if (GetShaderInfo(client_id)) {
+        SetGLError(GL_INVALID_OPERATION,
+                   (std::string(function_name) +
+                    ": shader passed for program").c_str());
+      } else {
+        SetGLError(GL_INVALID_VALUE,
+                   (std::string(function_name) + ": unknown program").c_str());
+      }
+    }
+    return info;
+  }
+
+
   // Deletes the program info for the given program.
   void RemoveProgramInfo(GLuint client_id) {
     program_manager()->RemoveProgramInfo(client_id);
@@ -525,6 +544,25 @@
     return (info && !info->IsDeleted()) ? info : NULL;
   }
 
+  // Gets the shader info for the given shader. If it's not a shader generates a
+  // GL error. Returns NULL if not shader.
+  ShaderManager::ShaderInfo* GetShaderInfoNotProgram(
+      GLuint client_id, const char* function_name) {
+    ShaderManager::ShaderInfo* info = GetShaderInfo(client_id);
+    if (!info) {
+      if (GetProgramInfo(client_id)) {
+        SetGLError(
+            GL_INVALID_OPERATION,
+            (std::string(function_name) +
+             ": program passed for shader").c_str());
+      } else {
+        SetGLError(GL_INVALID_VALUE,
+                   (std::string(function_name) + ": unknown shader").c_str());
+      }
+    }
+    return info;
+  }
+
   // Deletes the shader info for the given shader.
   void RemoveShaderInfo(GLuint client_id) {
     shader_manager()->RemoveShaderInfo(client_id);
@@ -1949,6 +1987,87 @@
       *num_written = 1;
       *params = GL_TRUE;
       return true;
+    case GL_ARRAY_BUFFER_BINDING:
+      *num_written = 1;
+      if (bound_array_buffer_) {
+        GLuint client_id = 0;
+        buffer_manager()->GetClientId(bound_array_buffer_->service_id(),
+                                      &client_id);
+        *params = client_id;
+      } else {
+        *params = 0;
+      }
+      return true;
+    case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+      *num_written = 1;
+      if (bound_element_array_buffer_) {
+        GLuint client_id = 0;
+        buffer_manager()->GetClientId(bound_element_array_buffer_->service_id(),
+                                      &client_id);
+        *params = client_id;
+      } else {
+        *params = 0;
+      }
+      return true;
+    case GL_FRAMEBUFFER_BINDING:
+      *num_written = 1;
+      if (bound_framebuffer_) {
+        GLuint client_id = 0;
+        framebuffer_manager()->GetClientId(
+            bound_framebuffer_->service_id(), &client_id);
+        *params = client_id;
+      } else {
+        *params = 0;
+      }
+      return true;
+    case GL_RENDERBUFFER_BINDING:
+      *num_written = 1;
+      if (bound_renderbuffer_) {
+        GLuint client_id = 0;
+        renderbuffer_manager()->GetClientId(
+            bound_renderbuffer_->service_id(), &client_id);
+        *params = client_id;
+      } else {
+        *params = 0;
+      }
+      return true;
+    case GL_CURRENT_PROGRAM:
+      *num_written = 1;
+      if (current_program_) {
+        GLuint client_id = 0;
+        program_manager()->GetClientId(
+            current_program_->service_id(), &client_id);
+        *params = client_id;
+      } else {
+        *params = 0;
+      }
+      return true;
+    case GL_TEXTURE_BINDING_2D: {
+        *num_written = 1;
+        TextureUnit& unit = texture_units_[active_texture_unit_];
+        if (unit.bound_texture_2d) {
+          GLuint client_id = 0;
+          texture_manager()->GetClientId(
+              unit.bound_texture_2d->service_id(), &client_id);
+          *params = client_id;
+        } else {
+          *params = 0;
+        }
+        return true;
+      }
+    case GL_TEXTURE_BINDING_CUBE_MAP: {
+        *num_written = 1;
+        TextureUnit& unit = texture_units_[active_texture_unit_];
+        if (unit.bound_texture_cube_map) {
+          GLuint client_id = 0;
+          texture_manager()->GetClientId(
+              unit.bound_texture_cube_map->service_id(), &client_id);
+          *params = client_id;
+        } else {
+          *params = 0;
+        }
+        return true;
+      }
     default:
       return false;
   }
@@ -1992,9 +2111,9 @@
 
 void GLES2DecoderImpl::DoGetProgramiv(
     GLuint program_id, GLenum pname, GLint* params) {
-  ProgramManager::ProgramInfo* info = GetProgramInfo(program_id);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program_id, "glGetProgramiv");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetProgramiv: unknown program");
     return;
   }
   info->GetProgramiv(pname, params);
@@ -2002,9 +2121,10 @@
 
 error::Error GLES2DecoderImpl::HandleBindAttribLocation(
     uint32 immediate_data_size, const gles2::BindAttribLocation& c) {
-  ProgramManager::ProgramInfo* info = GetProgramInfo(c.program);
+  GLuint program = static_cast<GLuint>(c.program);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glBindAttribLocation");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glBindAttribLocation: unknown program");
     return error::kNoError;
   }
   GLuint index = static_cast<GLuint>(c.index);
@@ -2021,9 +2141,10 @@
 
 error::Error GLES2DecoderImpl::HandleBindAttribLocationImmediate(
     uint32 immediate_data_size, const gles2::BindAttribLocationImmediate& c) {
-  ProgramManager::ProgramInfo* info = GetProgramInfo(c.program);
+  GLuint program = static_cast<GLuint>(c.program);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glBindAttribLocation");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glBindAttribLocation: unknown program");
     return error::kNoError;
   }
   GLuint index = static_cast<GLuint>(c.index);
@@ -2040,9 +2161,10 @@
 
 error::Error GLES2DecoderImpl::HandleBindAttribLocationBucket(
     uint32 immediate_data_size, const gles2::BindAttribLocationBucket& c) {
-  ProgramManager::ProgramInfo* info = GetProgramInfo(c.program);
+  GLuint program = static_cast<GLuint>(c.program);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glBindAttribLocation");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glBindAttribLocation: unknown program");
     return error::kNoError;
   }
   GLuint index = static_cast<GLuint>(c.index);
@@ -2283,19 +2405,18 @@
 }
 
 void GLES2DecoderImpl::DoLinkProgram(GLuint program) {
-  ProgramManager::ProgramInfo* info = GetProgramInfo(program);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glLinkProgram");
   if (!info) {
-    SetGLError(GL_INVALID_OPERATION, "glLinkProgram: unknown program");
     return;
   }
-  CopyRealGLErrorsToWrapper();
   glLinkProgram(info->service_id());
-  GLenum error = glGetError();
-  if (error != GL_NO_ERROR) {
-    info->Reset();
-    SetGLError(error, NULL);
-  } else {
+  GLint success = 0;
+  glGetProgramiv(info->service_id(), GL_LINK_STATUS, &success);
+  if (success) {
     info->Update();
+  } else {
+    info->Reset();
   }
 };
 
@@ -2368,9 +2489,8 @@
   GLuint service_id = 0;
   ProgramManager::ProgramInfo* info = NULL;
   if (program) {
-    info = GetProgramInfo(program);
+    info = GetProgramInfoNotShader(program, "glUseProgram");
     if (!info) {
-      SetGLError(GL_INVALID_VALUE, "glUseProgram: unknown program");
       return;
     }
     if (!info->IsValid()) {
@@ -2618,9 +2738,9 @@
 // memory.)
 error::Error GLES2DecoderImpl::ShaderSourceHelper(
     GLuint client_id, const char* data, uint32 data_size) {
-  ShaderManager::ShaderInfo* info = GetShaderInfo(client_id);
+  ShaderManager::ShaderInfo* info = GetShaderInfoNotProgram(
+      client_id, "glShaderSource");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glShaderSource: unknown shader");
     return error::kNoError;
   }
   // Note: We don't actually call glShaderSource here. We wait until
@@ -2663,9 +2783,9 @@
 }
 
 void GLES2DecoderImpl::DoCompileShader(GLuint client_id) {
-  ShaderManager::ShaderInfo* info = GetShaderInfo(client_id);
+  ShaderManager::ShaderInfo* info = GetShaderInfoNotProgram(
+      client_id, "glCompileShader");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glCompileShader: unknown shader");
     return;
   }
   // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
@@ -2711,9 +2831,9 @@
 
 void GLES2DecoderImpl::DoGetShaderiv(
     GLuint shader, GLenum pname, GLint* params) {
-  ShaderManager::ShaderInfo* info = GetShaderInfo(shader);
+  ShaderManager::ShaderInfo* info = GetShaderInfoNotProgram(
+      shader, "glGetShaderiv");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetShaderiv: unknown shader");
     return;
   }
   if (pname == GL_SHADER_SOURCE_LENGTH) {
@@ -2726,12 +2846,12 @@
 error::Error GLES2DecoderImpl::HandleGetShaderSource(
     uint32 immediate_data_size, const gles2::GetShaderSource& c) {
   GLuint shader = c.shader;
-  ShaderManager::ShaderInfo* info = GetShaderInfo(shader);
   uint32 bucket_id = static_cast<uint32>(c.bucket_id);
   Bucket* bucket = CreateBucket(bucket_id);
+  ShaderManager::ShaderInfo* info = GetShaderInfoNotProgram(
+      shader, "glGetShaderSource");
   if (!info) {
     bucket->SetSize(0);
-    SetGLError(GL_INVALID_VALUE, "glGetShaderSource: unknown shader");
     return error::kNoError;
   }
   bucket->SetFromString(info->source());
@@ -2741,15 +2861,15 @@
 error::Error GLES2DecoderImpl::HandleGetProgramInfoLog(
     uint32 immediate_data_size, const gles2::GetProgramInfoLog& c) {
   GLuint program = c.program;
-  ProgramManager::ProgramInfo* info = GetProgramInfo(program);
+  uint32 bucket_id = static_cast<uint32>(c.bucket_id);
+  Bucket* bucket = CreateBucket(bucket_id);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glGetProgramInfoLog");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetProgramInfoLog: unknown program");
     return error::kNoError;
   }
-  uint32 bucket_id = static_cast<uint32>(c.bucket_id);
   GLint len = 0;
   glGetProgramiv(info->service_id(), GL_INFO_LOG_LENGTH, &len);
-  Bucket* bucket = CreateBucket(bucket_id);
   bucket->SetSize(len + 1);
   glGetProgramInfoLog(
       info->service_id(),
@@ -2760,15 +2880,16 @@
 error::Error GLES2DecoderImpl::HandleGetShaderInfoLog(
     uint32 immediate_data_size, const gles2::GetShaderInfoLog& c) {
   GLuint shader = c.shader;
-  ShaderManager::ShaderInfo* info = GetShaderInfo(shader);
+  uint32 bucket_id = static_cast<uint32>(c.bucket_id);
+  Bucket* bucket = CreateBucket(bucket_id);
+  ShaderManager::ShaderInfo* info = GetShaderInfoNotProgram(
+      shader, "glGetShaderInfoLog");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetShaderInfoLog: unknown shader");
+    bucket->SetSize(0);
     return error::kNoError;
   }
-  uint32 bucket_id = static_cast<uint32>(c.bucket_id);
   GLint len = 0;
   glGetShaderiv(info->service_id(), GL_INFO_LOG_LENGTH, &len);
-  Bucket* bucket = CreateBucket(bucket_id);
   bucket->SetSize(len + 1);
   glGetShaderInfoLog(
       info->service_id(),
@@ -2802,14 +2923,14 @@
 
 void GLES2DecoderImpl::DoAttachShader(
     GLuint program_client_id, GLint shader_client_id) {
-  ProgramManager::ProgramInfo* program_info = GetProgramInfo(program_client_id);
+  ProgramManager::ProgramInfo* program_info = GetProgramInfoNotShader(
+      program_client_id, "glAttachShader");
   if (!program_info) {
-    SetGLError(GL_INVALID_VALUE, "glAttachShader: unknown program");
     return;
   }
-  ShaderManager::ShaderInfo* shader_info = GetShaderInfo(shader_client_id);
+  ShaderManager::ShaderInfo* shader_info = GetShaderInfoNotProgram(
+      shader_client_id, "glAttachShader");
   if (!shader_info) {
-    SetGLError(GL_INVALID_VALUE, "glAttachShader: unknown shader");
     return;
   }
   glAttachShader(program_info->service_id(), shader_info->service_id());
@@ -2817,23 +2938,23 @@
 
 void GLES2DecoderImpl::DoDetachShader(
     GLuint program_client_id, GLint shader_client_id) {
-  ProgramManager::ProgramInfo* program_info = GetProgramInfo(program_client_id);
+  ProgramManager::ProgramInfo* program_info = GetProgramInfoNotShader(
+      program_client_id, "glDetachShader");
   if (!program_info) {
-    SetGLError(GL_INVALID_VALUE, "glDetachShader: unknown program");
     return;
   }
-  ShaderManager::ShaderInfo* shader_info = GetShaderInfo(shader_client_id);
+  ShaderManager::ShaderInfo* shader_info = GetShaderInfoNotProgram(
+      shader_client_id, "glDetachShader");
   if (!shader_info) {
-    SetGLError(GL_INVALID_VALUE, "glDetachShader: unknown shader");
     return;
   }
   glDetachShader(program_info->service_id(), shader_info->service_id());
 }
 
 void GLES2DecoderImpl::DoValidateProgram(GLuint program_client_id) {
-  ProgramManager::ProgramInfo* info = GetProgramInfo(program_client_id);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program_client_id, "glValidateProgram");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glValidateProgram: unknown program");
     return;
   }
   glValidateProgram(info->service_id());
@@ -2951,6 +3072,7 @@
     return error::kNoError;
   }
 
+  glFinish();
   if (x < 0 || y < 0 || max_x > max_size.width() || max_y > max_size.height()) {
     // The user requested an out of range area. Get the results 1 line
     // at a time.
@@ -3041,9 +3163,9 @@
 error::Error GLES2DecoderImpl::GetAttribLocationHelper(
     GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
     const std::string& name_str) {
-  ProgramManager::ProgramInfo* info = GetProgramInfo(client_id);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      client_id, "glGetAttribLocation");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetAttribLocation: unknown program");
     return error::kNoError;
   }
   if (!info->IsValid()) {
@@ -3105,9 +3227,9 @@
 error::Error GLES2DecoderImpl::GetUniformLocationHelper(
     GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
     const std::string& name_str) {
-  ProgramManager::ProgramInfo* info = GetProgramInfo(client_id);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      client_id, "glUniformLocation");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetUniformLocation: unknown program");
     return error::kNoError;
   }
   if (!info->IsValid()) {
@@ -3518,9 +3640,9 @@
   *result_pointer = result;
   // Set the result size to 0 so the client does not have to check for success.
   result->SetNumResults(0);
-  ProgramManager::ProgramInfo* info = GetProgramInfo(program);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glGetUniform");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetUniform: unknown program");
     return false;
   }
   if (!info->IsValid()) {
@@ -3636,9 +3758,10 @@
 error::Error GLES2DecoderImpl::HandleGetAttachedShaders(
     uint32 immediate_data_size, const gles2::GetAttachedShaders& c) {
   uint32 result_size = c.result_size;
-  ProgramManager::ProgramInfo* info = GetProgramInfo(c.program);
+  GLuint program = static_cast<GLuint>(c.program);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glGetAttachedShaders");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders: unknown program");
     return error::kNoError;
   }
   typedef gles2::GetAttachedShaders::Result Result;
@@ -3681,14 +3804,9 @@
   if (result->success != 0) {
     return error::kInvalidArguments;
   }
-  ProgramManager::ProgramInfo* info = GetProgramInfo(program);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glGetActiveUniform");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetActiveUniform: unknown program");
-    return error::kNoError;
-  }
-  if (!info->IsValid()) {
-    // Program was not linked successfully. (ie, glLinkProgram)
-    SetGLError(GL_INVALID_OPERATION, "glGetActiveUniform: program not linked");
     return error::kNoError;
   }
   const ProgramManager::ProgramInfo::UniformInfo* uniform_info =
@@ -3720,14 +3838,9 @@
   if (result->success != 0) {
     return error::kInvalidArguments;
   }
-  ProgramManager::ProgramInfo* info = GetProgramInfo(program);
+  ProgramManager::ProgramInfo* info = GetProgramInfoNotShader(
+      program, "glGetActiveAttrib");
   if (!info) {
-    SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib: unknown program");
-    return error::kNoError;
-  }
-  if (!info->IsValid()) {
-    // Program was not linked successfully. (ie, glLinkProgram)
-    SetGLError(GL_INVALID_OPERATION, "glGetActiveAttrib: program not linked");
     return error::kNoError;
   }
   const ProgramManager::ProgramInfo::VertexAttribInfo* attrib_info =
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 759e54c..859e4d3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -1317,6 +1317,7 @@
   GLint read_end_y = std::max(0, std::min(kHeight, in_read_y + in_read_height));
   GLint read_width = read_end_x - read_x;
   GLint read_height = read_end_y - read_y;
+  EXPECT_CALL(*gl_, Finish()).Times(1).RetiresOnSaturation();
   if (read_width > 0 && read_height > 0) {
     for (GLint yy = read_y; yy < read_end_y; ++yy) {
       EXPECT_CALL(
@@ -1399,6 +1400,7 @@
      .WillOnce(Return(GL_NO_ERROR))
      .WillOnce(Return(GL_NO_ERROR))
      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, Finish()).Times(1).RetiresOnSaturation();
   EXPECT_CALL(
       *gl_, ReadPixels(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, _))
       .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels));
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
index caadef6..832e0c5 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
@@ -34,11 +34,9 @@
 
 template <>
 void GLES2DecoderTestBase::SpecializedSetup<LinkProgram, 0>() {
-  EXPECT_CALL(*gl_, GetError())
-      .WillOnce(Return(GL_NO_ERROR))
-      .WillOnce(Return(GL_NO_ERROR))
-      .RetiresOnSaturation();
   InSequence dummy;
+  EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+      .WillOnce(SetArgumentPointee<2>(1));
   EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_ATTRIBUTES, _))
       .WillOnce(SetArgumentPointee<2>(0));
   EXPECT_CALL(
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 9da6955..e16f0a4 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -296,14 +296,11 @@
 
   {
     InSequence s;
-    EXPECT_CALL(*gl_, GetError())
-        .WillOnce(Return(GL_NO_ERROR))
-        .RetiresOnSaturation();
     EXPECT_CALL(*gl_, LinkProgram(service_id))
         .Times(1)
         .RetiresOnSaturation();
-    EXPECT_CALL(*gl_, GetError())
-        .WillOnce(Return(GL_NO_ERROR))
+    EXPECT_CALL(*gl_, GetProgramiv(service_id, GL_LINK_STATUS, _))
+        .WillOnce(SetArgumentPointee<2>(1))
         .RetiresOnSaturation();
     EXPECT_CALL(*gl_,
         GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTES, _))
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index afd9bce..5b86014a 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -51,7 +51,8 @@
     }
   }
 
-  GLint num_uniforms;
+  GLint num_uniforms = 0;
+  max_len = 0;
   glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
   glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
   name_buffer.reset(new char[max_len]);
@@ -257,6 +258,18 @@
   }
 }
 
+bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
+  // This doesn't need to be fast. It's only used during slow queries.
+  for (ProgramInfoMap::const_iterator it = program_infos_.begin();
+       it != program_infos_.end(); ++it) {
+    if (it->second->service_id() == service_id) {
+      *client_id = it->first;
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 078f8a5..feb263c 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -168,6 +168,9 @@
   // Deletes the program info for the given program.
   void RemoveProgramInfo(GLuint client_id);
 
+  // Gets a client id for a given service id.
+  bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
   // Returns true if prefix is invalid for gl.
   static bool IsInvalidPrefix(const char* name, size_t length);
 
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index b8b318c..6767646 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -47,6 +47,9 @@
   ProgramManager::ProgramInfo* info1 = manager_.GetProgramInfo(kClient1Id);
   ASSERT_TRUE(info1 != NULL);
   EXPECT_EQ(kService1Id, info1->service_id());
+  GLuint client_id = 0;
+  EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id));
+  EXPECT_EQ(kClient1Id, client_id);
   // Check we get nothing for a non-existent program.
   EXPECT_TRUE(manager_.GetProgramInfo(kClient2Id) == NULL);
   // Check trying to a remove non-existent programs does not crash.
diff --git a/gpu/command_buffer/service/renderbuffer_manager.cc b/gpu/command_buffer/service/renderbuffer_manager.cc
index fe07d01..63aee26 100644
--- a/gpu/command_buffer/service/renderbuffer_manager.cc
+++ b/gpu/command_buffer/service/renderbuffer_manager.cc
@@ -34,6 +34,19 @@
   }
 }
 
+bool RenderbufferManager::GetClientId(
+    GLuint service_id, GLuint* client_id) const {
+  // This doesn't need to be fast. It's only used during slow queries.
+  for (RenderbufferInfoMap::const_iterator it = renderbuffer_infos_.begin();
+       it != renderbuffer_infos_.end(); ++it) {
+    if (it->second->service_id() == service_id) {
+      *client_id = it->first;
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/service/renderbuffer_manager.h b/gpu/command_buffer/service/renderbuffer_manager.h
index 8e2f70b..e896117 100644
--- a/gpu/command_buffer/service/renderbuffer_manager.h
+++ b/gpu/command_buffer/service/renderbuffer_manager.h
@@ -73,6 +73,9 @@
   // Removes a renderbuffer info for the given renderbuffer.
   void RemoveRenderbufferInfo(GLuint client_id);
 
+  // Gets a client id for a given service id.
+  bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
  private:
   // Info for each renderbuffer in the system.
   // TODO(gman): Choose a faster container.
diff --git a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
index bebd8fce..0cedaea 100644
--- a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
@@ -33,6 +33,9 @@
   RenderbufferManager::RenderbufferInfo* info1 =
       manager_.GetRenderbufferInfo(kClient1Id);
   ASSERT_TRUE(info1 != NULL);
+  GLuint client_id = 0;
+  EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id));
+  EXPECT_EQ(kClient1Id, client_id);
   EXPECT_FALSE(info1->cleared());
   info1->set_cleared();
   EXPECT_TRUE(info1->cleared());
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index 50af31af..9c5fa3e 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -47,6 +47,9 @@
   TextureManager::TextureInfo* info1 = manager_.GetTextureInfo(kClient1Id);
   ASSERT_TRUE(info1 != NULL);
   EXPECT_EQ(kService1Id, info1->service_id());
+  GLuint client_id = 0;
+  EXPECT_TRUE(manager_.GetClientId(info1->service_id(), &client_id));
+  EXPECT_EQ(kClient1Id, client_id);
   // Check we get nothing for a non-existent texture.
   EXPECT_TRUE(manager_.GetTextureInfo(kClient2Id) == NULL);
   // Check trying to a remove non-existent textures does not crash.