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 |