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
3 // found in the LICENSE file.
5 #include "gpu/command_buffer/service/program_manager.h"
12 #include "base/basictypes.h"
13 #include "base/command_line.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/metrics/histogram.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/time/time.h"
19 #include "gpu/command_buffer/common/gles2_cmd_format.h"
20 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
21 #include "gpu/command_buffer/service/feature_info.h"
22 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
23 #include "gpu/command_buffer/service/gpu_switches.h"
24 #include "gpu/command_buffer/service/program_cache.h"
25 #include "gpu/command_buffer/service/shader_manager.h"
26 #include "gpu/command_buffer/service/shader_translator.h"
27 #include "third_party/re2/re2/re2.h"
29 using base::TimeDelta;
30 using base::TimeTicks;
38 explicit UniformType(const ShaderTranslator::VariableInfo uniform)
41 precision(uniform.precision) { }
46 precision(SH_PRECISION_MEDIUMP) { }
48 bool operator==(const UniformType& other) const {
49 return type == other.type &&
51 precision == other.precision;
59 int ShaderTypeToIndex(GLenum shader_type) {
60 switch (shader_type) {
61 case GL_VERTEX_SHADER:
63 case GL_FRAGMENT_SHADER:
71 // Given a name like "foo.bar[123].moo[456]" sets new_name to "foo.bar[123].moo"
72 // and sets element_index to 456. returns false if element expression was not a
73 // whole decimal number. For example: "foo[1b2]"
74 bool GetUniformNameSansElement(
75 const std::string& name, int* element_index, std::string* new_name) {
76 DCHECK(element_index);
78 if (name.size() < 3 || name[name.size() - 1] != ']') {
84 // Look for an array specification.
85 size_t open_pos = name.find_last_of('[');
86 if (open_pos == std::string::npos ||
87 open_pos >= name.size() - 2) {
92 size_t last = name.size() - 1;
93 for (size_t pos = open_pos + 1; pos < last; ++pos) {
94 int8 digit = name[pos] - '0';
95 if (digit < 0 || digit > 9) {
98 index = index * 10 + digit;
101 *element_index = index;
102 *new_name = name.substr(0, open_pos);
106 bool IsBuiltInVarying(const std::string& name) {
107 // Built-in variables.
108 const char* kBuiltInVaryings[] = {
113 for (size_t ii = 0; ii < arraysize(kBuiltInVaryings); ++ii) {
114 if (name == kBuiltInVaryings[ii])
120 } // anonymous namespace.
122 Program::UniformInfo::UniformInfo()
125 fake_location_base(0),
129 Program::UniformInfo::UniformInfo(
132 int _fake_location_base,
133 const std::string& _name)
136 fake_location_base(_fake_location_base),
141 Program::UniformInfo::~UniformInfo() {}
143 bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
144 static const char kInvalidPrefix[] = { 'g', 'l', '_' };
145 return (length >= sizeof(kInvalidPrefix) &&
146 memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
150 ProgramManager* manager, GLuint service_id)
153 max_attrib_name_length_(0),
154 max_uniform_name_length_(0),
155 service_id_(service_id),
159 uniforms_cleared_(false),
161 manager_->StartTracking(this);
164 void Program::Reset() {
166 link_status_ = false;
168 max_uniform_name_length_ = 0;
169 max_attrib_name_length_ = 0;
170 attrib_infos_.clear();
171 uniform_infos_.clear();
172 sampler_indices_.clear();
173 attrib_location_to_index_map_.clear();
176 std::string Program::ProcessLogInfo(
177 const std::string& log) {
179 re2::StringPiece input(log);
180 std::string prior_log;
181 std::string hashed_name;
182 while (RE2::Consume(&input,
183 "(.*?)(webgl_[0123456789abcdefABCDEF]+)",
188 const std::string* original_name =
189 GetOriginalNameFromHashedName(hashed_name);
191 output += *original_name;
193 output += hashed_name;
196 return output + input.as_string();
199 void Program::UpdateLogInfo() {
201 glGetProgramiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
206 scoped_ptr<char[]> temp(new char[max_len]);
208 glGetProgramInfoLog(service_id_, max_len, &len, temp.get());
209 DCHECK(max_len == 0 || len < max_len);
210 DCHECK(len == 0 || temp[len] == '\0');
211 std::string log(temp.get(), len);
212 set_log_info(ProcessLogInfo(log).c_str());
215 void Program::ClearUniforms(
216 std::vector<uint8>* zero_buffer) {
218 if (uniforms_cleared_) {
221 uniforms_cleared_ = true;
222 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
223 const UniformInfo& uniform_info = uniform_infos_[ii];
224 if (!uniform_info.IsValid()) {
227 GLint location = uniform_info.element_locations[0];
228 GLsizei size = uniform_info.size;
229 uint32 unit_size = GLES2Util::GetGLDataTypeSizeForUniforms(
231 uint32 size_needed = size * unit_size;
232 if (size_needed > zero_buffer->size()) {
233 zero_buffer->resize(size_needed, 0u);
235 const void* zero = &(*zero_buffer)[0];
236 switch (uniform_info.type) {
238 glUniform1fv(location, size, reinterpret_cast<const GLfloat*>(zero));
241 glUniform2fv(location, size, reinterpret_cast<const GLfloat*>(zero));
244 glUniform3fv(location, size, reinterpret_cast<const GLfloat*>(zero));
247 glUniform4fv(location, size, reinterpret_cast<const GLfloat*>(zero));
252 case GL_SAMPLER_CUBE:
253 case GL_SAMPLER_EXTERNAL_OES:
254 case GL_SAMPLER_3D_OES:
255 case GL_SAMPLER_2D_RECT_ARB:
256 glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero));
260 glUniform2iv(location, size, reinterpret_cast<const GLint*>(zero));
264 glUniform3iv(location, size, reinterpret_cast<const GLint*>(zero));
268 glUniform4iv(location, size, reinterpret_cast<const GLint*>(zero));
272 location, size, false, reinterpret_cast<const GLfloat*>(zero));
276 location, size, false, reinterpret_cast<const GLfloat*>(zero));
280 location, size, false, reinterpret_cast<const GLfloat*>(zero));
292 UniformData() : size(-1), type(GL_NONE), location(0), added(false) {
294 std::string queried_name;
295 std::string corrected_name;
296 std::string original_name;
303 struct UniformDataComparer {
304 bool operator()(const UniformData& lhs, const UniformData& rhs) const {
305 return lhs.queried_name < rhs.queried_name;
309 } // anonymous namespace
311 void Program::Update() {
315 uniforms_cleared_ = false;
316 GLint num_attribs = 0;
318 GLint max_location = -1;
319 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs);
320 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
321 // TODO(gman): Should we check for error?
322 scoped_ptr<char[]> name_buffer(new char[max_len]);
323 for (GLint ii = 0; ii < num_attribs; ++ii) {
328 service_id_, ii, max_len, &length, &size, &type, name_buffer.get());
329 DCHECK(max_len == 0 || length < max_len);
330 DCHECK(length == 0 || name_buffer[length] == '\0');
331 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
333 std::string original_name;
334 GetCorrectedVariableInfo(
335 false, name_buffer.get(), &name, &original_name, &size, &type);
336 // TODO(gman): Should we check for error?
337 GLint location = glGetAttribLocation(service_id_, name_buffer.get());
338 if (location > max_location) {
339 max_location = location;
341 attrib_infos_.push_back(
342 VertexAttrib(size, type, original_name, location));
343 max_attrib_name_length_ = std::max(
344 max_attrib_name_length_, static_cast<GLsizei>(original_name.size()));
348 // Create attrib location to index map.
349 attrib_location_to_index_map_.resize(max_location + 1);
350 for (GLint ii = 0; ii <= max_location; ++ii) {
351 attrib_location_to_index_map_[ii] = -1;
353 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
354 const VertexAttrib& info = attrib_infos_[ii];
355 attrib_location_to_index_map_[info.location] = ii;
359 if (CommandLine::ForCurrentProcess()->HasSwitch(
360 switches::kEnableGPUServiceLoggingGPU)) {
361 DVLOG(1) << "----: attribs for service_id: " << service_id();
362 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
363 const VertexAttrib& info = attrib_infos_[ii];
364 DVLOG(1) << ii << ": loc = " << info.location
365 << ", size = " << info.size
366 << ", type = " << GLES2Util::GetStringEnum(info.type)
367 << ", name = " << info.name;
373 GLint num_uniforms = 0;
374 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
375 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
376 name_buffer.reset(new char[max_len]);
378 // Reads all the names.
379 std::vector<UniformData> uniform_data;
380 for (GLint ii = 0; ii < num_uniforms; ++ii) {
384 service_id_, ii, max_len, &length,
385 &data.size, &data.type, name_buffer.get());
386 DCHECK(max_len == 0 || length < max_len);
387 DCHECK(length == 0 || name_buffer[length] == '\0');
388 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
389 data.queried_name = std::string(name_buffer.get());
390 GetCorrectedVariableInfo(
391 true, name_buffer.get(), &data.corrected_name, &data.original_name,
392 &data.size, &data.type);
393 uniform_data.push_back(data);
397 // NOTE: We don't care if 2 uniforms are bound to the same location.
398 // One of them will take preference. The spec allows this, same as
399 // BindAttribLocation.
401 // The reason we don't check is if we were to fail we'd have to
402 // restore the previous program but since we've already linked successfully
403 // at this point the previous program is gone.
405 // Assigns the uniforms with bindings.
406 size_t next_available_index = 0;
407 for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
408 UniformData& data = uniform_data[ii];
409 data.location = glGetUniformLocation(
410 service_id_, data.queried_name.c_str());
412 std::string short_name;
413 int element_index = 0;
414 bool good ALLOW_UNUSED = GetUniformNameSansElement(
415 data.queried_name, &element_index, &short_name);\
417 LocationMap::const_iterator it = bind_uniform_location_map_.find(
419 if (it != bind_uniform_location_map_.end()) {
420 data.added = AddUniformInfo(
421 data.size, data.type, data.location, it->second, data.corrected_name,
422 data.original_name, &next_available_index);
426 // Assigns the uniforms that were not bound.
427 for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
428 const UniformData& data = uniform_data[ii];
431 data.size, data.type, data.location, -1, data.corrected_name,
432 data.original_name, &next_available_index);
437 if (CommandLine::ForCurrentProcess()->HasSwitch(
438 switches::kEnableGPUServiceLoggingGPU)) {
439 DVLOG(1) << "----: uniforms for service_id: " << service_id();
440 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
441 const UniformInfo& info = uniform_infos_[ii];
442 if (info.IsValid()) {
443 DVLOG(1) << ii << ": loc = " << info.element_locations[0]
444 << ", size = " << info.size
445 << ", type = " << GLES2Util::GetStringEnum(info.type)
446 << ", name = " << info.name;
455 void Program::ExecuteBindAttribLocationCalls() {
456 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
457 it != bind_attrib_location_map_.end(); ++it) {
458 const std::string* mapped_name = GetAttribMappedName(it->first);
459 if (mapped_name && *mapped_name != it->first)
460 glBindAttribLocation(service_id_, it->second, mapped_name->c_str());
464 void ProgramManager::DoCompileShader(Shader* shader,
465 ShaderTranslator* translator,
466 FeatureInfo* feature_info) {
467 // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
468 // glShaderSource and then glCompileShader.
469 const std::string* source = shader->source();
470 const char* shader_src = source ? source->c_str() : "";
472 if (!translator->Translate(shader_src)) {
473 shader->SetStatus(false, translator->info_log(), NULL);
476 shader_src = translator->translated_shader();
477 if (!feature_info->feature_flags().angle_translated_shader_source)
478 shader->UpdateTranslatedSource(shader_src);
481 glShaderSource(shader->service_id(), 1, &shader_src, NULL);
482 glCompileShader(shader->service_id());
483 if (feature_info->feature_flags().angle_translated_shader_source) {
485 glGetShaderiv(shader->service_id(),
486 GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
488 scoped_ptr<char[]> temp(new char[max_len]);
490 glGetTranslatedShaderSourceANGLE(
491 shader->service_id(), max_len, &len, temp.get());
492 DCHECK(max_len == 0 || len < max_len);
493 DCHECK(len == 0 || temp[len] == '\0');
494 shader->UpdateTranslatedSource(max_len ? temp.get() : NULL);
497 GLint status = GL_FALSE;
498 glGetShaderiv(shader->service_id(), GL_COMPILE_STATUS, &status);
500 shader->SetStatus(true, "", translator);
502 // We cannot reach here if we are using the shader translator.
503 // All invalid shaders must be rejected by the translator.
504 // All translated shaders must compile.
506 glGetShaderiv(shader->service_id(), GL_INFO_LOG_LENGTH, &max_len);
507 scoped_ptr<char[]> temp(new char[max_len]);
509 glGetShaderInfoLog(shader->service_id(), max_len, &len, temp.get());
510 DCHECK(max_len == 0 || len < max_len);
511 DCHECK(len == 0 || temp[len] == '\0');
512 shader->SetStatus(false, std::string(temp.get(), len).c_str(), NULL);
513 LOG_IF(ERROR, translator)
514 << "Shader translator allowed/produced an invalid shader "
515 << "unless the driver is buggy:"
516 << "\n--original-shader--\n" << (source ? *source : std::string())
517 << "\n--translated-shader--\n" << shader_src << "\n--info-log--\n"
518 << *shader->log_info();
522 bool Program::Link(ShaderManager* manager,
523 ShaderTranslator* vertex_translator,
524 ShaderTranslator* fragment_translator,
525 FeatureInfo* feature_info,
526 const ShaderCacheCallback& shader_callback) {
529 set_log_info("missing shaders");
532 if (DetectAttribLocationBindingConflicts()) {
533 set_log_info("glBindAttribLocation() conflicts");
536 std::string conflicting_name;
537 if (DetectUniformsMismatch(&conflicting_name)) {
538 std::string info_log = "Uniforms with the same name but different "
539 "type/precision: " + conflicting_name;
540 set_log_info(ProcessLogInfo(info_log).c_str());
543 if (DetectVaryingsMismatch(&conflicting_name)) {
544 std::string info_log = "Varyings with the same name but different type, "
545 "or statically used varyings in fragment shader are "
546 "not declared in vertex shader: " + conflicting_name;
547 set_log_info(ProcessLogInfo(info_log).c_str());
550 if (DetectGlobalNameConflicts(&conflicting_name)) {
551 std::string info_log = "Name conflicts between an uniform and an "
552 "attribute: " + conflicting_name;
553 set_log_info(ProcessLogInfo(info_log).c_str());
556 if (!CheckVaryingsPacking()) {
557 set_log_info("Varyings over maximum register limit");
561 TimeTicks before_time = TimeTicks::HighResNow();
563 ProgramCache* cache = manager_->program_cache_;
565 DCHECK(attached_shaders_[0]->signature_source() &&
566 attached_shaders_[1]->signature_source());
567 ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
568 *attached_shaders_[0]->signature_source(),
570 *attached_shaders_[1]->signature_source(),
572 &bind_attrib_location_map_);
574 if (status == ProgramCache::LINK_SUCCEEDED) {
575 ProgramCache::ProgramLoadResult success =
576 cache->LoadLinkedProgram(service_id(),
577 attached_shaders_[0].get(),
579 attached_shaders_[1].get(),
581 &bind_attrib_location_map_,
583 link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
584 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
589 ExecuteBindAttribLocationCalls();
590 before_time = TimeTicks::HighResNow();
591 if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
592 glProgramParameteri(service_id(),
593 PROGRAM_BINARY_RETRIEVABLE_HINT,
596 glLinkProgram(service_id());
600 glGetProgramiv(service_id(), GL_LINK_STATUS, &success);
601 if (success == GL_TRUE) {
605 cache->SaveLinkedProgram(service_id(),
606 attached_shaders_[0].get(),
608 attached_shaders_[1].get(),
610 &bind_attrib_location_map_,
613 UMA_HISTOGRAM_CUSTOM_COUNTS(
614 "GPU.ProgramCache.BinaryCacheMissTime",
615 (TimeTicks::HighResNow() - before_time).InMicroseconds(),
617 TimeDelta::FromSeconds(10).InMicroseconds(),
620 UMA_HISTOGRAM_CUSTOM_COUNTS(
621 "GPU.ProgramCache.BinaryCacheHitTime",
622 (TimeTicks::HighResNow() - before_time).InMicroseconds(),
624 TimeDelta::FromSeconds(1).InMicroseconds(),
630 return success == GL_TRUE;
633 void Program::Validate() {
635 set_log_info("program not linked");
638 glValidateProgram(service_id());
642 GLint Program::GetUniformFakeLocation(
643 const std::string& name) const {
644 bool getting_array_location = false;
645 size_t open_pos = std::string::npos;
647 if (!GLES2Util::ParseUniformName(
648 name, &open_pos, &index, &getting_array_location)) {
651 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
652 const UniformInfo& info = uniform_infos_[ii];
653 if (!info.IsValid()) {
656 if (info.name == name ||
658 info.name.compare(0, info.name.size() - 3, name) == 0)) {
659 return info.fake_location_base;
660 } else if (getting_array_location && info.is_array) {
661 // Look for an array specification.
662 size_t open_pos_2 = info.name.find_last_of('[');
663 if (open_pos_2 == open_pos &&
664 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
665 if (index >= 0 && index < info.size) {
666 DCHECK_GT(static_cast<int>(info.element_locations.size()), index);
667 if (info.element_locations[index] == -1)
669 return ProgramManager::MakeFakeLocation(
670 info.fake_location_base, index);
678 GLint Program::GetAttribLocation(
679 const std::string& name) const {
680 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
681 const VertexAttrib& info = attrib_infos_[ii];
682 if (info.name == name) {
683 return info.location;
689 const Program::UniformInfo*
690 Program::GetUniformInfoByFakeLocation(
691 GLint fake_location, GLint* real_location, GLint* array_index) const {
692 DCHECK(real_location);
694 if (fake_location < 0) {
698 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
699 if (uniform_index >= 0 &&
700 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
701 const UniformInfo& uniform_info = uniform_infos_[uniform_index];
702 if (!uniform_info.IsValid()) {
705 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
706 if (element_index < uniform_info.size) {
707 *real_location = uniform_info.element_locations[element_index];
708 *array_index = element_index;
709 return &uniform_info;
715 const std::string* Program::GetAttribMappedName(
716 const std::string& original_name) const {
717 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
718 Shader* shader = attached_shaders_[ii].get();
720 const std::string* mapped_name =
721 shader->GetAttribMappedName(original_name);
729 const std::string* Program::GetOriginalNameFromHashedName(
730 const std::string& hashed_name) const {
731 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
732 Shader* shader = attached_shaders_[ii].get();
734 const std::string* original_name =
735 shader->GetOriginalNameFromHashedName(hashed_name);
737 return original_name;
743 bool Program::SetUniformLocationBinding(
744 const std::string& name, GLint location) {
745 std::string short_name;
746 int element_index = 0;
747 if (!GetUniformNameSansElement(name, &element_index, &short_name) ||
748 element_index != 0) {
752 bind_uniform_location_map_[short_name] = location;
756 // Note: This is only valid to call right after a program has been linked
758 void Program::GetCorrectedVariableInfo(
760 const std::string& name, std::string* corrected_name,
761 std::string* original_name,
762 GLsizei* size, GLenum* type) const {
763 DCHECK(corrected_name);
764 DCHECK(original_name);
767 const char* kArraySpec = "[0]";
768 for (int jj = 0; jj < 2; ++jj) {
769 std::string test_name(name + ((jj == 1) ? kArraySpec : ""));
770 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
771 Shader* shader = attached_shaders_[ii].get();
773 const Shader::VariableInfo* variable_info =
774 use_uniforms ? shader->GetUniformInfo(test_name) :
775 shader->GetAttribInfo(test_name);
776 // Note: There is an assuption here that if an attrib is defined in more
777 // than 1 attached shader their types and sizes match. Should we check
780 *corrected_name = test_name;
781 *original_name = variable_info->name;
782 *type = variable_info->type;
783 *size = variable_info->size;
789 *corrected_name = name;
790 *original_name = name;
793 bool Program::AddUniformInfo(
794 GLsizei size, GLenum type, GLint location, GLint fake_base_location,
795 const std::string& name, const std::string& original_name,
796 size_t* next_available_index) {
797 DCHECK(next_available_index);
798 const char* kArraySpec = "[0]";
799 size_t uniform_index =
800 fake_base_location >= 0 ? fake_base_location : *next_available_index;
801 if (uniform_infos_.size() < uniform_index + 1) {
802 uniform_infos_.resize(uniform_index + 1);
805 // return if this location is already in use.
806 if (uniform_infos_[uniform_index].IsValid()) {
807 DCHECK_GE(fake_base_location, 0);
811 uniform_infos_[uniform_index] = UniformInfo(
812 size, type, uniform_index, original_name);
815 UniformInfo& info = uniform_infos_[uniform_index];
816 info.element_locations.resize(size);
817 info.element_locations[0] = location;
819 size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
820 info.texture_units.clear();
821 info.texture_units.resize(num_texture_units, 0);
824 // Go through the array element locations looking for a match.
825 // We can skip the first element because it's the same as the
826 // the location without the array operators.
827 size_t array_pos = name.rfind(kArraySpec);
828 std::string base_name = name;
829 if (name.size() > 3) {
830 if (array_pos != name.size() - 3) {
831 info.name = name + kArraySpec;
833 base_name = name.substr(0, name.size() - 3);
836 for (GLsizei ii = 1; ii < info.size; ++ii) {
837 std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
838 info.element_locations[ii] =
839 glGetUniformLocation(service_id_, element_name.c_str());
845 (info.name.size() > 3 &&
846 info.name.rfind(kArraySpec) == info.name.size() - 3));
848 if (info.IsSampler()) {
849 sampler_indices_.push_back(info.fake_location_base);
851 max_uniform_name_length_ =
852 std::max(max_uniform_name_length_,
853 static_cast<GLsizei>(info.name.size()));
855 while (*next_available_index < uniform_infos_.size() &&
856 uniform_infos_[*next_available_index].IsValid()) {
857 *next_available_index = *next_available_index + 1;
863 const Program::UniformInfo*
864 Program::GetUniformInfo(
866 if (static_cast<size_t>(index) >= uniform_infos_.size()) {
870 const UniformInfo& info = uniform_infos_[index];
871 return info.IsValid() ? &info : NULL;
874 bool Program::SetSamplers(
875 GLint num_texture_units, GLint fake_location,
876 GLsizei count, const GLint* value) {
877 if (fake_location < 0) {
880 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
881 if (uniform_index >= 0 &&
882 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
883 UniformInfo& info = uniform_infos_[uniform_index];
884 if (!info.IsValid()) {
887 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
888 if (element_index < info.size) {
889 count = std::min(info.size - element_index, count);
890 if (info.IsSampler() && count > 0) {
891 for (GLsizei ii = 0; ii < count; ++ii) {
892 if (value[ii] < 0 || value[ii] >= num_texture_units) {
896 std::copy(value, value + count,
897 info.texture_units.begin() + element_index);
905 void Program::GetProgramiv(GLenum pname, GLint* params) {
907 case GL_ACTIVE_ATTRIBUTES:
908 *params = attrib_infos_.size();
910 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
911 // Notice +1 to accomodate NULL terminator.
912 *params = max_attrib_name_length_ + 1;
914 case GL_ACTIVE_UNIFORMS:
915 *params = num_uniforms_;
917 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
918 // Notice +1 to accomodate NULL terminator.
919 *params = max_uniform_name_length_ + 1;
922 *params = link_status_;
924 case GL_INFO_LOG_LENGTH:
925 // Notice +1 to accomodate NULL terminator.
926 *params = log_info_.get() ? (log_info_->size() + 1) : 0;
928 case GL_DELETE_STATUS:
931 case GL_VALIDATE_STATUS:
935 glGetProgramiv(service_id_, pname, params);
939 glGetProgramiv(service_id_, pname, params);
944 bool Program::AttachShader(
945 ShaderManager* shader_manager,
947 DCHECK(shader_manager);
949 int index = ShaderTypeToIndex(shader->shader_type());
950 if (attached_shaders_[index].get() != NULL) {
953 attached_shaders_[index] = scoped_refptr<Shader>(shader);
954 shader_manager->UseShader(shader);
958 bool Program::DetachShader(
959 ShaderManager* shader_manager,
961 DCHECK(shader_manager);
963 if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() !=
967 attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL;
968 shader_manager->UnuseShader(shader);
972 void Program::DetachShaders(ShaderManager* shader_manager) {
973 DCHECK(shader_manager);
974 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
975 if (attached_shaders_[ii].get()) {
976 DetachShader(shader_manager, attached_shaders_[ii].get());
981 bool Program::CanLink() const {
982 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
983 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid()) {
990 bool Program::DetectAttribLocationBindingConflicts() const {
991 std::set<GLint> location_binding_used;
992 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
993 it != bind_attrib_location_map_.end(); ++it) {
994 // Find out if an attribute is declared in this program's shaders.
996 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
997 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid())
999 if (attached_shaders_[ii]->GetAttribInfo(it->first)) {
1005 std::pair<std::set<GLint>::iterator, bool> result =
1006 location_binding_used.insert(it->second);
1014 bool Program::DetectUniformsMismatch(std::string* conflicting_name) const {
1015 typedef std::map<std::string, UniformType> UniformMap;
1016 UniformMap uniform_map;
1017 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1018 const ShaderTranslator::VariableMap& shader_uniforms =
1019 attached_shaders_[ii]->uniform_map();
1020 for (ShaderTranslator::VariableMap::const_iterator iter =
1021 shader_uniforms.begin();
1022 iter != shader_uniforms.end(); ++iter) {
1023 const std::string& name = iter->first;
1024 UniformType type(iter->second);
1025 UniformMap::iterator map_entry = uniform_map.find(name);
1026 if (map_entry == uniform_map.end()) {
1027 uniform_map[name] = type;
1029 // If a uniform is already in the map, i.e., it has already been
1030 // declared by other shader, then the type and precision must match.
1031 if (map_entry->second == type)
1033 *conflicting_name = name;
1041 bool Program::DetectVaryingsMismatch(std::string* conflicting_name) const {
1042 DCHECK(attached_shaders_[0] &&
1043 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1044 attached_shaders_[1] &&
1045 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1046 const ShaderTranslator::VariableMap* vertex_varyings =
1047 &(attached_shaders_[0]->varying_map());
1048 const ShaderTranslator::VariableMap* fragment_varyings =
1049 &(attached_shaders_[1]->varying_map());
1051 for (ShaderTranslator::VariableMap::const_iterator iter =
1052 fragment_varyings->begin();
1053 iter != fragment_varyings->end(); ++iter) {
1054 const std::string& name = iter->first;
1055 if (IsBuiltInVarying(name))
1058 ShaderTranslator::VariableMap::const_iterator hit =
1059 vertex_varyings->find(name);
1060 if (hit == vertex_varyings->end()) {
1061 if (iter->second.static_use) {
1062 *conflicting_name = name;
1068 if (hit->second.type != iter->second.type ||
1069 hit->second.size != iter->second.size) {
1070 *conflicting_name = name;
1078 bool Program::DetectGlobalNameConflicts(std::string* conflicting_name) const {
1079 DCHECK(attached_shaders_[0] &&
1080 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1081 attached_shaders_[1] &&
1082 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1083 const ShaderTranslator::VariableMap* uniforms[2];
1084 uniforms[0] = &(attached_shaders_[0]->uniform_map());
1085 uniforms[1] = &(attached_shaders_[1]->uniform_map());
1086 const ShaderTranslator::VariableMap* attribs =
1087 &(attached_shaders_[0]->attrib_map());
1089 for (ShaderTranslator::VariableMap::const_iterator iter =
1090 attribs->begin(); iter != attribs->end(); ++iter) {
1091 for (int ii = 0; ii < 2; ++ii) {
1092 if (uniforms[ii]->find(iter->first) != uniforms[ii]->end()) {
1093 *conflicting_name = iter->first;
1101 bool Program::CheckVaryingsPacking() const {
1102 DCHECK(attached_shaders_[0] &&
1103 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1104 attached_shaders_[1] &&
1105 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1106 const ShaderTranslator::VariableMap* vertex_varyings =
1107 &(attached_shaders_[0]->varying_map());
1108 const ShaderTranslator::VariableMap* fragment_varyings =
1109 &(attached_shaders_[1]->varying_map());
1111 std::map<std::string, ShVariableInfo> combined_map;
1113 for (ShaderTranslator::VariableMap::const_iterator iter =
1114 fragment_varyings->begin();
1115 iter != fragment_varyings->end(); ++iter) {
1116 if (!iter->second.static_use)
1118 if (!IsBuiltInVarying(iter->first)) {
1119 ShaderTranslator::VariableMap::const_iterator vertex_iter =
1120 vertex_varyings->find(iter->first);
1121 if (vertex_iter == vertex_varyings->end() ||
1122 !vertex_iter->second.static_use)
1127 var.type = static_cast<ShDataType>(iter->second.type);
1128 var.size = iter->second.size;
1129 combined_map[iter->first] = var;
1132 if (combined_map.size() == 0)
1134 scoped_ptr<ShVariableInfo[]> variables(
1135 new ShVariableInfo[combined_map.size()]);
1137 for (std::map<std::string, ShVariableInfo>::const_iterator iter =
1138 combined_map.begin();
1139 iter != combined_map.end(); ++iter) {
1140 variables[index].type = iter->second.type;
1141 variables[index].size = iter->second.size;
1144 return ShCheckVariablesWithinPackingLimits(
1145 static_cast<int>(manager_->max_varying_vectors()),
1147 combined_map.size()) == 1;
1150 static uint32 ComputeOffset(const void* start, const void* position) {
1151 return static_cast<const uint8*>(position) -
1152 static_cast<const uint8*>(start);
1155 void Program::GetProgramInfo(
1156 ProgramManager* manager, CommonDecoder::Bucket* bucket) const {
1157 // NOTE: It seems to me the math in here does not need check for overflow
1158 // because the data being calucated from has various small limits. The max
1159 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1160 // of an identifier is 256 characters.
1161 uint32 num_locations = 0;
1162 uint32 total_string_size = 0;
1164 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1165 const VertexAttrib& info = attrib_infos_[ii];
1167 total_string_size += info.name.size();
1170 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1171 const UniformInfo& info = uniform_infos_[ii];
1172 if (info.IsValid()) {
1173 num_locations += info.element_locations.size();
1174 total_string_size += info.name.size();
1178 uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
1179 uint32 input_size = num_inputs * sizeof(ProgramInput);
1180 uint32 location_size = num_locations * sizeof(int32);
1181 uint32 size = sizeof(ProgramInfoHeader) +
1182 input_size + location_size + total_string_size;
1184 bucket->SetSize(size);
1185 ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
1186 ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
1187 sizeof(ProgramInfoHeader), input_size);
1188 int32* locations = bucket->GetDataAs<int32*>(
1189 sizeof(ProgramInfoHeader) + input_size, location_size);
1190 char* strings = bucket->GetDataAs<char*>(
1191 sizeof(ProgramInfoHeader) + input_size + location_size,
1198 header->link_status = link_status_;
1199 header->num_attribs = attrib_infos_.size();
1200 header->num_uniforms = num_uniforms_;
1202 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1203 const VertexAttrib& info = attrib_infos_[ii];
1204 inputs->size = info.size;
1205 inputs->type = info.type;
1206 inputs->location_offset = ComputeOffset(header, locations);
1207 inputs->name_offset = ComputeOffset(header, strings);
1208 inputs->name_length = info.name.size();
1209 *locations++ = info.location;
1210 memcpy(strings, info.name.c_str(), info.name.size());
1211 strings += info.name.size();
1215 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1216 const UniformInfo& info = uniform_infos_[ii];
1217 if (info.IsValid()) {
1218 inputs->size = info.size;
1219 inputs->type = info.type;
1220 inputs->location_offset = ComputeOffset(header, locations);
1221 inputs->name_offset = ComputeOffset(header, strings);
1222 inputs->name_length = info.name.size();
1223 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
1224 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
1225 if (info.element_locations[jj] == -1)
1228 *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
1230 memcpy(strings, info.name.c_str(), info.name.size());
1231 strings += info.name.size();
1236 DCHECK_EQ(ComputeOffset(header, strings), size);
1239 Program::~Program() {
1241 if (manager_->have_context_) {
1242 glDeleteProgram(service_id());
1244 manager_->StopTracking(this);
1250 ProgramManager::ProgramManager(ProgramCache* program_cache,
1251 uint32 max_varying_vectors)
1252 : program_count_(0),
1253 have_context_(true),
1254 disable_workarounds_(
1255 CommandLine::ForCurrentProcess()->HasSwitch(
1256 switches::kDisableGpuDriverBugWorkarounds)),
1257 program_cache_(program_cache),
1258 max_varying_vectors_(max_varying_vectors) { }
1260 ProgramManager::~ProgramManager() {
1261 DCHECK(programs_.empty());
1264 void ProgramManager::Destroy(bool have_context) {
1265 have_context_ = have_context;
1269 void ProgramManager::StartTracking(Program* /* program */) {
1273 void ProgramManager::StopTracking(Program* /* program */) {
1277 Program* ProgramManager::CreateProgram(
1278 GLuint client_id, GLuint service_id) {
1279 std::pair<ProgramMap::iterator, bool> result =
1281 std::make_pair(client_id,
1282 scoped_refptr<Program>(
1283 new Program(this, service_id))));
1284 DCHECK(result.second);
1285 return result.first->second.get();
1288 Program* ProgramManager::GetProgram(GLuint client_id) {
1289 ProgramMap::iterator it = programs_.find(client_id);
1290 return it != programs_.end() ? it->second.get() : NULL;
1293 bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
1294 // This doesn't need to be fast. It's only used during slow queries.
1295 for (ProgramMap::const_iterator it = programs_.begin();
1296 it != programs_.end(); ++it) {
1297 if (it->second->service_id() == service_id) {
1298 *client_id = it->first;
1305 ProgramCache* ProgramManager::program_cache() const {
1306 return program_cache_;
1309 bool ProgramManager::IsOwned(Program* program) {
1310 for (ProgramMap::iterator it = programs_.begin();
1311 it != programs_.end(); ++it) {
1312 if (it->second.get() == program) {
1319 void ProgramManager::RemoveProgramInfoIfUnused(
1320 ShaderManager* shader_manager, Program* program) {
1321 DCHECK(shader_manager);
1323 DCHECK(IsOwned(program));
1324 if (program->IsDeleted() && !program->InUse()) {
1325 program->DetachShaders(shader_manager);
1326 for (ProgramMap::iterator it = programs_.begin();
1327 it != programs_.end(); ++it) {
1328 if (it->second.get() == program) {
1329 programs_.erase(it);
1337 void ProgramManager::MarkAsDeleted(
1338 ShaderManager* shader_manager,
1340 DCHECK(shader_manager);
1342 DCHECK(IsOwned(program));
1343 program->MarkAsDeleted();
1344 RemoveProgramInfoIfUnused(shader_manager, program);
1347 void ProgramManager::UseProgram(Program* program) {
1349 DCHECK(IsOwned(program));
1350 program->IncUseCount();
1351 ClearUniforms(program);
1354 void ProgramManager::UnuseProgram(
1355 ShaderManager* shader_manager,
1357 DCHECK(shader_manager);
1359 DCHECK(IsOwned(program));
1360 program->DecUseCount();
1361 RemoveProgramInfoIfUnused(shader_manager, program);
1364 void ProgramManager::ClearUniforms(Program* program) {
1366 if (!disable_workarounds_) {
1367 program->ClearUniforms(&zero_);
1371 int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
1372 return index + element * 0x10000;
1375 } // namespace gles2