| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "gpu/command_buffer/service/program_manager.h" | 5 #include "gpu/command_buffer/service/program_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <vector> |
| 9 | 10 |
| 10 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 11 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 12 #include "base/logging.h" | 13 #include "base/logging.h" |
| 13 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 14 #include "base/string_number_conversions.h" | 15 #include "base/string_number_conversions.h" |
| 15 #include "gpu/command_buffer/common/gles2_cmd_format.h" | 16 #include "gpu/command_buffer/common/gles2_cmd_format.h" |
| 16 #include "gpu/command_buffer/common/gles2_cmd_utils.h" | 17 #include "gpu/command_buffer/common/gles2_cmd_utils.h" |
| 17 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | 18 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
| 18 #include "gpu/command_buffer/service/gpu_switches.h" | 19 #include "gpu/command_buffer/service/gpu_switches.h" |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 glUniformMatrix4fv( | 157 glUniformMatrix4fv( |
| 157 location, size, false, reinterpret_cast<const GLfloat*>(zero)); | 158 location, size, false, reinterpret_cast<const GLfloat*>(zero)); |
| 158 break; | 159 break; |
| 159 default: | 160 default: |
| 160 NOTREACHED(); | 161 NOTREACHED(); |
| 161 break; | 162 break; |
| 162 } | 163 } |
| 163 } | 164 } |
| 164 } | 165 } |
| 165 | 166 |
| 167 namespace { |
| 168 |
| 169 struct UniformData { |
| 170 std::string queried_name; |
| 171 std::string corrected_name; |
| 172 std::string original_name; |
| 173 GLsizei size; |
| 174 GLenum type; |
| 175 }; |
| 176 |
| 177 struct UniformDataComparer { |
| 178 bool operator()(const UniformData& lhs, const UniformData& rhs) const { |
| 179 return lhs.queried_name < rhs.queried_name; |
| 180 } |
| 181 }; |
| 182 |
| 183 } // anonymous namespace |
| 184 |
| 166 void ProgramManager::ProgramInfo::Update() { | 185 void ProgramManager::ProgramInfo::Update() { |
| 167 Reset(); | 186 Reset(); |
| 168 UpdateLogInfo(); | 187 UpdateLogInfo(); |
| 169 link_status_ = true; | 188 link_status_ = true; |
| 170 uniforms_cleared_ = false; | 189 uniforms_cleared_ = false; |
| 171 GLint num_attribs = 0; | 190 GLint num_attribs = 0; |
| 172 GLint max_len = 0; | 191 GLint max_len = 0; |
| 173 GLint max_location = -1; | 192 GLint max_location = -1; |
| 174 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs); | 193 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs); |
| 175 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len); | 194 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) { | 227 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) { |
| 209 const VertexAttribInfo& info = attrib_infos_[ii]; | 228 const VertexAttribInfo& info = attrib_infos_[ii]; |
| 210 attrib_location_to_index_map_[info.location] = ii; | 229 attrib_location_to_index_map_[info.location] = ii; |
| 211 } | 230 } |
| 212 | 231 |
| 213 max_len = 0; | 232 max_len = 0; |
| 214 GLint num_uniforms = 0; | 233 GLint num_uniforms = 0; |
| 215 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms); | 234 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms); |
| 216 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len); | 235 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len); |
| 217 name_buffer.reset(new char[max_len]); | 236 name_buffer.reset(new char[max_len]); |
| 237 |
| 238 // Read all the names first and sort them so we get a consistent list |
| 239 std::vector<UniformData> uniform_data_; |
| 218 for (GLint ii = 0; ii < num_uniforms; ++ii) { | 240 for (GLint ii = 0; ii < num_uniforms; ++ii) { |
| 219 GLsizei length = 0; | 241 GLsizei length = 0; |
| 220 GLsizei size = 0; | 242 UniformData data; |
| 221 GLenum type = 0; | |
| 222 glGetActiveUniform( | 243 glGetActiveUniform( |
| 223 service_id_, ii, max_len, &length, &size, &type, name_buffer.get()); | 244 service_id_, ii, max_len, &length, |
| 245 &data.size, &data.type, name_buffer.get()); |
| 224 DCHECK(max_len == 0 || length < max_len); | 246 DCHECK(max_len == 0 || length < max_len); |
| 225 DCHECK(length == 0 || name_buffer[length] == '\0'); | 247 DCHECK(length == 0 || name_buffer[length] == '\0'); |
| 226 // TODO(gman): Should we check for error? | |
| 227 if (!IsInvalidPrefix(name_buffer.get(), length)) { | 248 if (!IsInvalidPrefix(name_buffer.get(), length)) { |
| 228 GLint location = glGetUniformLocation(service_id_, name_buffer.get()); | 249 data.queried_name = std::string(name_buffer.get()); |
| 229 std::string name; | |
| 230 std::string original_name; | |
| 231 GetCorrectedVariableInfo( | 250 GetCorrectedVariableInfo( |
| 232 true, name_buffer.get(), &name, &original_name, &size, &type); | 251 true, name_buffer.get(), &data.corrected_name, &data.original_name, |
| 233 const UniformInfo* info = AddUniformInfo( | 252 &data.size, &data.type); |
| 234 size, type, location, name, original_name); | 253 uniform_data_.push_back(data); |
| 235 if (info->IsSampler()) { | |
| 236 sampler_indices_.push_back(info->fake_location_base); | |
| 237 } | |
| 238 max_uniform_name_length_ = | |
| 239 std::max(max_uniform_name_length_, | |
| 240 static_cast<GLsizei>(info->name.size())); | |
| 241 } | 254 } |
| 242 } | 255 } |
| 256 |
| 257 std::sort(uniform_data_.begin(), uniform_data_.end(), UniformDataComparer()); |
| 258 |
| 259 for (size_t ii = 0; ii < uniform_data_.size(); ++ii) { |
| 260 const UniformData& data = uniform_data_[ii]; |
| 261 GLint location = glGetUniformLocation( |
| 262 service_id_, data.queried_name.c_str()); |
| 263 const UniformInfo* info = AddUniformInfo( |
| 264 data.size, data.type, location, data.corrected_name, |
| 265 data.original_name); |
| 266 if (info->IsSampler()) { |
| 267 sampler_indices_.push_back(info->fake_location_base); |
| 268 } |
| 269 max_uniform_name_length_ = |
| 270 std::max(max_uniform_name_length_, |
| 271 static_cast<GLsizei>(info->name.size())); |
| 272 } |
| 243 valid_ = true; | 273 valid_ = true; |
| 244 } | 274 } |
| 245 | 275 |
| 246 void ProgramManager::ProgramInfo::ExecuteBindAttribLocationCalls() { | 276 void ProgramManager::ProgramInfo::ExecuteBindAttribLocationCalls() { |
| 247 for (std::map<std::string, GLint>::const_iterator it = | 277 for (std::map<std::string, GLint>::const_iterator it = |
| 248 bind_attrib_location_map_.begin(); | 278 bind_attrib_location_map_.begin(); |
| 249 it != bind_attrib_location_map_.end(); ++it) { | 279 it != bind_attrib_location_map_.end(); ++it) { |
| 250 const std::string* mapped_name = GetAttribMappedName(it->first); | 280 const std::string* mapped_name = GetAttribMappedName(it->first); |
| 251 if (mapped_name && *mapped_name != it->first) | 281 if (mapped_name && *mapped_name != it->first) |
| 252 glBindAttribLocation(service_id_, it->second, mapped_name->c_str()); | 282 glBindAttribLocation(service_id_, it->second, mapped_name->c_str()); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 bool bad = false; | 335 bool bad = false; |
| 306 for (size_t pos = open_pos + 1; pos < last; ++pos) { | 336 for (size_t pos = open_pos + 1; pos < last; ++pos) { |
| 307 int8 digit = name[pos] - '0'; | 337 int8 digit = name[pos] - '0'; |
| 308 if (digit < 0 || digit > 9) { | 338 if (digit < 0 || digit > 9) { |
| 309 bad = true; | 339 bad = true; |
| 310 break; | 340 break; |
| 311 } | 341 } |
| 312 index = index * 10 + digit; | 342 index = index * 10 + digit; |
| 313 } | 343 } |
| 314 if (!bad && index >= 0 && index < info.size) { | 344 if (!bad && index >= 0 && index < info.size) { |
| 315 return GetFakeLocation(info.fake_location_base, index); | 345 return GLES2Util::MakeFakeLocation(info.fake_location_base, index); |
| 316 } | 346 } |
| 317 } | 347 } |
| 318 } | 348 } |
| 319 } | 349 } |
| 320 return -1; | 350 return -1; |
| 321 } | 351 } |
| 322 | 352 |
| 323 GLint ProgramManager::ProgramInfo::GetAttribLocation( | 353 GLint ProgramManager::ProgramInfo::GetAttribLocation( |
| 324 const std::string& name) const { | 354 const std::string& name) const { |
| 325 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) { | 355 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) { |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 | 681 |
| 652 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) { | 682 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) { |
| 653 const UniformInfo& info = uniform_infos_[ii]; | 683 const UniformInfo& info = uniform_infos_[ii]; |
| 654 inputs->size = info.size; | 684 inputs->size = info.size; |
| 655 inputs->type = info.type; | 685 inputs->type = info.type; |
| 656 inputs->location_offset = ComputeOffset(header, locations); | 686 inputs->location_offset = ComputeOffset(header, locations); |
| 657 inputs->name_offset = ComputeOffset(header, strings); | 687 inputs->name_offset = ComputeOffset(header, strings); |
| 658 inputs->name_length = info.name.size(); | 688 inputs->name_length = info.name.size(); |
| 659 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size()); | 689 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size()); |
| 660 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) { | 690 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) { |
| 661 *locations++ = manager->SwizzleLocation(ii + jj * 0x10000); | 691 *locations++ = GLES2Util::SwizzleLocation( |
| 692 GLES2Util::MakeFakeLocation(ii, jj)); |
| 662 } | 693 } |
| 663 memcpy(strings, info.name.c_str(), info.name.size()); | 694 memcpy(strings, info.name.c_str(), info.name.size()); |
| 664 strings += info.name.size(); | 695 strings += info.name.size(); |
| 665 ++inputs; | 696 ++inputs; |
| 666 } | 697 } |
| 667 | 698 |
| 668 DCHECK_EQ(ComputeOffset(header, strings), size); | 699 DCHECK_EQ(ComputeOffset(header, strings), size); |
| 669 } | 700 } |
| 670 | 701 |
| 671 ProgramManager::ProgramInfo::~ProgramInfo() { | 702 ProgramManager::ProgramInfo::~ProgramInfo() { |
| 672 if (manager_) { | 703 if (manager_) { |
| 673 if (manager_->have_context_) { | 704 if (manager_->have_context_) { |
| 674 glDeleteProgram(service_id()); | 705 glDeleteProgram(service_id()); |
| 675 } | 706 } |
| 676 manager_->StopTracking(this); | 707 manager_->StopTracking(this); |
| 677 manager_ = NULL; | 708 manager_ = NULL; |
| 678 } | 709 } |
| 679 } | 710 } |
| 680 | 711 |
| 681 // TODO(gman): make this some kind of random number. Base::RandInt is not | |
| 682 // callable because of the sandbox. What matters is that it's possibly different | |
| 683 // by at least 1 bit each time chrome is run. | |
| 684 static int uniform_random_offset_ = 3; | |
| 685 | |
| 686 ProgramManager::ProgramManager() | 712 ProgramManager::ProgramManager() |
| 687 : uniform_swizzle_(uniform_random_offset_++ % 15), | 713 : program_info_count_(0), |
| 688 program_info_count_(0), | |
| 689 have_context_(true), | 714 have_context_(true), |
| 690 disable_workarounds_( | 715 disable_workarounds_( |
| 691 CommandLine::ForCurrentProcess()->HasSwitch( | 716 CommandLine::ForCurrentProcess()->HasSwitch( |
| 692 switches::kDisableGpuDriverBugWorkarounds)) { | 717 switches::kDisableGpuDriverBugWorkarounds)) { |
| 693 } | 718 } |
| 694 | 719 |
| 695 ProgramManager::~ProgramManager() { | 720 ProgramManager::~ProgramManager() { |
| 696 DCHECK(program_infos_.empty()); | 721 DCHECK(program_infos_.empty()); |
| 697 } | 722 } |
| 698 | 723 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 791 RemoveProgramInfoIfUnused(shader_manager, info); | 816 RemoveProgramInfoIfUnused(shader_manager, info); |
| 792 } | 817 } |
| 793 | 818 |
| 794 void ProgramManager::ClearUniforms(ProgramManager::ProgramInfo* info) { | 819 void ProgramManager::ClearUniforms(ProgramManager::ProgramInfo* info) { |
| 795 DCHECK(info); | 820 DCHECK(info); |
| 796 if (!disable_workarounds_) { | 821 if (!disable_workarounds_) { |
| 797 info->ClearUniforms(&zero_); | 822 info->ClearUniforms(&zero_); |
| 798 } | 823 } |
| 799 } | 824 } |
| 800 | 825 |
| 801 // Swizzles the locations to prevent developers from assuming they | |
| 802 // can do math on uniforms. According to the OpenGL ES 2.0 spec | |
| 803 // the location of "someuniform[1]" is not 'n' more than "someuniform[0]". | |
| 804 static GLint Swizzle(GLint location) { | |
| 805 return (location & 0xF0000000U) | | |
| 806 ((location & 0x0AAAAAAAU) >> 1) | | |
| 807 ((location & 0x05555555U) << 1); | |
| 808 } | |
| 809 | |
| 810 // Adds uniform_swizzle_ to prevent developers from assuming that locations are | |
| 811 // always the same across GPUs and drivers. | |
| 812 GLint ProgramManager::SwizzleLocation(GLint v) const { | |
| 813 return v < 0 ? v : (Swizzle(v) + uniform_swizzle_); | |
| 814 } | |
| 815 | |
| 816 GLint ProgramManager::UnswizzleLocation(GLint v) const { | |
| 817 return v < 0 ? v : Swizzle(v - uniform_swizzle_); | |
| 818 } | |
| 819 | |
| 820 } // namespace gles2 | 826 } // namespace gles2 |
| 821 } // namespace gpu | 827 } // namespace gpu |
| 822 | 828 |
| 823 | 829 |
| OLD | NEW |