| // Copyright (c) 2010 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/program_manager.h" |
| #include "base/basictypes.h" |
| #include "base/logging.h" |
| #include "base/scoped_ptr.h" |
| #include "base/string_util.h" |
| #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) { |
| static const char kInvalidPrefix[] = { 'g', 'l', '_' }; |
| return (length >= sizeof(kInvalidPrefix) && |
| memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0); |
| } |
| |
| void ProgramManager::ProgramInfo::Update() { |
| GLint num_attribs = 0; |
| GLint max_len = 0; |
| glGetProgramiv(program_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs); |
| attrib_infos_.resize(num_attribs); |
| glGetProgramiv(program_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len); |
| // TODO(gman): Should we check for error? |
| scoped_array<char> name_buffer(new char[max_len]); |
| for (GLint ii = 0; ii < num_attribs; ++ii) { |
| GLsizei length; |
| GLsizei size; |
| GLenum type; |
| glGetActiveAttrib( |
| program_id_, ii, max_len, &length, &size, &type, name_buffer.get()); |
| // TODO(gman): Should we check for error? |
| GLint location = IsInvalidPrefix(name_buffer.get(), length) ? -1 : |
| glGetAttribLocation(program_id_, name_buffer.get()); |
| SetAttributeInfo(ii, size, type, location, name_buffer.get()); |
| } |
| GLint num_uniforms; |
| glGetProgramiv(program_id_, GL_ACTIVE_UNIFORMS, &num_uniforms); |
| uniform_infos_.resize(num_uniforms); |
| sampler_indices_.clear(); |
| glGetProgramiv(program_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len); |
| name_buffer.reset(new char[max_len]); |
| GLint max_location = -1; |
| for (GLint ii = 0; ii < num_uniforms; ++ii) { |
| GLsizei length; |
| GLsizei size; |
| GLenum type; |
| glGetActiveUniform( |
| program_id_, ii, max_len, &length, &size, &type, name_buffer.get()); |
| // TODO(gman): Should we check for error? |
| GLint location = IsInvalidPrefix(name_buffer.get(), length) ? -1 : |
| glGetUniformLocation(program_id_, name_buffer.get()); |
| SetUniformInfo(ii, size, type, location, name_buffer.get()); |
| const UniformInfo& info = uniform_infos_[ii]; |
| for (size_t jj = 0; jj < info.element_locations.size(); ++jj) { |
| if (info.element_locations[jj] > max_location) { |
| max_location = info.element_locations[jj]; |
| } |
| } |
| if (info.IsSampler()) { |
| sampler_indices_.push_back(ii); |
| } |
| } |
| // Create location to index map. |
| location_to_index_map_.resize(max_location + 1); |
| for (GLint ii = 0; ii <= max_location; ++ii) { |
| location_to_index_map_[ii] = -1; |
| } |
| for (GLint ii = 0; ii < num_uniforms; ++ii) { |
| const UniformInfo& info = uniform_infos_[ii]; |
| for (size_t jj = 0; jj < info.element_locations.size(); ++jj) { |
| location_to_index_map_[info.element_locations[jj]] = ii; |
| } |
| } |
| } |
| |
| GLint ProgramManager::ProgramInfo::GetUniformLocation(const std::string& name) { |
| for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) { |
| const UniformInfo& info = uniform_infos_[ii]; |
| if (info.name == name) { |
| return info.element_locations[0]; |
| } else if (name.size() >= 3 && name[name.size() - 1] == ']') { |
| // Look for an array specfication. |
| size_t open_pos = name.find_last_of('['); |
| if (open_pos != std::string::npos && open_pos < name.size() - 2) { |
| GLuint index = 0; |
| size_t last = name.size() - 1; |
| bool bad = false; |
| for (size_t pos = open_pos + 1; pos < last; ++pos) { |
| int8 digit = name[pos] - '0'; |
| if (digit < 0 || digit > 9) { |
| bad = true; |
| break; |
| } |
| index = index * 10 + digit; |
| } |
| if (!bad) { |
| return index; |
| } |
| } |
| } |
| } |
| return -1; |
| } |
| |
| GLint ProgramManager::ProgramInfo::GetAttribLocation( |
| const std::string& name) const { |
| for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) { |
| const VertexAttribInfo& info = attrib_infos_[ii]; |
| if (info.name == name) { |
| return info.location; |
| } |
| } |
| return -1; |
| } |
| |
| bool ProgramManager::ProgramInfo::GetUniformTypeByLocation( |
| GLint location, GLenum* type) const { |
| if (location >= 0 && |
| static_cast<size_t>(location) < location_to_index_map_.size()) { |
| GLint index = location_to_index_map_[location]; |
| if (index >= 0) { |
| *type = uniform_infos_[index].type; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void ProgramManager::ProgramInfo::SetUniformInfo( |
| GLint index, GLsizei size, GLenum type, GLint location, |
| const std::string& name) { |
| DCHECK(static_cast<unsigned>(index) < uniform_infos_.size()); |
| UniformInfo& info = uniform_infos_[index]; |
| info.size = size; |
| info.type = type; |
| info.name = name; |
| info.element_locations.resize(size); |
| info.element_locations[0] = location; |
| size_t num_texture_units = info.IsSampler() ? size : 0u; |
| info.texture_units.clear(); |
| info.texture_units.resize(num_texture_units, 0); |
| |
| // Go through the array element locations looking for a match. |
| // We can skip the first element because it's the same as the |
| // the location without the array operators. |
| if (size > 1) { |
| for (GLsizei ii = 1; ii < info.size; ++ii) { |
| std::string element_name(name + "[" + IntToString(ii) + "]"); |
| info.element_locations[ii] = |
| glGetUniformLocation(program_id_, element_name.c_str()); |
| } |
| } |
| } |
| |
| bool ProgramManager::ProgramInfo::SetSamplers( |
| GLint location, GLsizei count, const GLint* value) { |
| if (location >= 0 && |
| static_cast<size_t>(location) < location_to_index_map_.size()) { |
| GLint index = location_to_index_map_[location]; |
| if (index >= 0) { |
| UniformInfo& info = uniform_infos_[index]; |
| if (info.IsSampler() && count <= info.size) { |
| std::copy(value, value + count, info.texture_units.begin()); |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| void ProgramManager::CreateProgramInfo(GLuint program_id) { |
| std::pair<ProgramInfoMap::iterator, bool> result = |
| program_infos_.insert( |
| std::make_pair(program_id, |
| ProgramInfo::Ref(new ProgramInfo(program_id)))); |
| DCHECK(result.second); |
| } |
| |
| ProgramManager::ProgramInfo* ProgramManager::GetProgramInfo(GLuint program_id) { |
| ProgramInfoMap::iterator it = program_infos_.find(program_id); |
| return it != program_infos_.end() ? it->second : NULL; |
| } |
| |
| void ProgramManager::RemoveProgramInfo(GLuint program_id) { |
| ProgramInfoMap::iterator it = program_infos_.find(program_id); |
| if (it != program_infos_.end()) { |
| it->second->MarkAsDeleted(); |
| program_infos_.erase(it); |
| } |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |
| |