| Index: gpu/command_buffer/client/program_info_manager.cc
 | 
| diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc
 | 
| index 04121aa7346ba275391dc30102909c31d47cf304..779d914ac4c441a6fc40d0a00a958281a7df7c83 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::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::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 @@ GLint ProgramInfoManager::Program::GetUniformLocation(
 | 
|    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 @@ bool ProgramInfoManager::Program::GetProgramiv(
 | 
|      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 @@ GLuint ProgramInfoManager::Program::GetUniformBlockIndex(
 | 
|    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 @@ void ProgramInfoManager::Program::UpdateES3UniformBlocks(
 | 
|    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 @@ ProgramInfoManager::Program* ProgramInfoManager::GetProgramInfo(
 | 
|          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 @@ bool ProgramInfoManager::GetProgramiv(
 | 
|      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 @@ bool ProgramInfoManager::GetProgramiv(
 | 
|    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 @@ bool ProgramInfoManager::GetActiveUniformBlockiv(
 | 
|        }
 | 
|      }
 | 
|    }
 | 
| -  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
 | 
| 
 |