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/strings/string_util.h"
19 #include "base/time/time.h"
20 #include "gpu/command_buffer/common/gles2_cmd_format.h"
21 #include "gpu/command_buffer/common/gles2_cmd_utils.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;
37 int ShaderTypeToIndex(GLenum shader_type) {
38 switch (shader_type) {
39 case GL_VERTEX_SHADER:
41 case GL_FRAGMENT_SHADER:
49 // Given a name like "foo.bar[123].moo[456]" sets new_name to "foo.bar[123].moo"
50 // and sets element_index to 456. returns false if element expression was not a
51 // whole decimal number. For example: "foo[1b2]"
52 bool GetUniformNameSansElement(
53 const std::string& name, int* element_index, std::string* new_name) {
54 DCHECK(element_index);
56 if (name.size() < 3 || name[name.size() - 1] != ']') {
62 // Look for an array specification.
63 size_t open_pos = name.find_last_of('[');
64 if (open_pos == std::string::npos ||
65 open_pos >= name.size() - 2) {
70 size_t last = name.size() - 1;
71 for (size_t pos = open_pos + 1; pos < last; ++pos) {
72 int8 digit = name[pos] - '0';
73 if (digit < 0 || digit > 9) {
76 index = index * 10 + digit;
79 *element_index = index;
80 *new_name = name.substr(0, open_pos);
84 bool IsBuiltInFragmentVarying(const std::string& name) {
85 // Built-in variables for fragment shaders.
86 const char* kBuiltInVaryings[] = {
91 for (size_t ii = 0; ii < arraysize(kBuiltInVaryings); ++ii) {
92 if (name == kBuiltInVaryings[ii])
98 bool IsBuiltInInvariant(
99 const VaryingMap& varyings, const std::string& name) {
100 VaryingMap::const_iterator hit = varyings.find(name);
101 if (hit == varyings.end())
103 return hit->second.isInvariant;
106 } // anonymous namespace.
108 Program::UniformInfo::UniformInfo()
111 fake_location_base(0),
115 Program::UniformInfo::UniformInfo(GLsizei _size,
117 int _fake_location_base,
118 const std::string& _name)
122 fake_location_base(_fake_location_base),
127 accepts_api_type = kUniform1i;
130 accepts_api_type = kUniform2i;
133 accepts_api_type = kUniform3i;
136 accepts_api_type = kUniform4i;
140 accepts_api_type = kUniform1i | kUniform1f;
143 accepts_api_type = kUniform2i | kUniform2f;
146 accepts_api_type = kUniform3i | kUniform3f;
149 accepts_api_type = kUniform4i | kUniform4f;
153 accepts_api_type = kUniform1f;
156 accepts_api_type = kUniform2f;
159 accepts_api_type = kUniform3f;
162 accepts_api_type = kUniform4f;
166 accepts_api_type = kUniformMatrix2f;
169 accepts_api_type = kUniformMatrix3f;
172 accepts_api_type = kUniformMatrix4f;
176 case GL_SAMPLER_2D_RECT_ARB:
177 case GL_SAMPLER_CUBE:
178 case GL_SAMPLER_3D_OES:
179 case GL_SAMPLER_EXTERNAL_OES:
180 accepts_api_type = kUniform1i;
183 NOTREACHED() << "Unhandled UniformInfo type " << type;
188 Program::UniformInfo::~UniformInfo() {}
190 bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
191 static const char kInvalidPrefix[] = { 'g', 'l', '_' };
192 return (length >= sizeof(kInvalidPrefix) &&
193 memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
196 Program::Program(ProgramManager* manager, GLuint service_id)
199 max_attrib_name_length_(0),
200 max_uniform_name_length_(0),
201 service_id_(service_id),
205 uniforms_cleared_(false),
207 manager_->StartTracking(this);
210 void Program::Reset() {
212 link_status_ = false;
214 max_uniform_name_length_ = 0;
215 max_attrib_name_length_ = 0;
216 attrib_infos_.clear();
217 uniform_infos_.clear();
218 sampler_indices_.clear();
219 attrib_location_to_index_map_.clear();
222 std::string Program::ProcessLogInfo(
223 const std::string& log) {
225 re2::StringPiece input(log);
226 std::string prior_log;
227 std::string hashed_name;
228 while (RE2::Consume(&input,
229 "(.*?)(webgl_[0123456789abcdefABCDEF]+)",
234 const std::string* original_name =
235 GetOriginalNameFromHashedName(hashed_name);
237 output += *original_name;
239 output += hashed_name;
242 return output + input.as_string();
245 void Program::UpdateLogInfo() {
247 glGetProgramiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
252 scoped_ptr<char[]> temp(new char[max_len]);
254 glGetProgramInfoLog(service_id_, max_len, &len, temp.get());
255 DCHECK(max_len == 0 || len < max_len);
256 DCHECK(len == 0 || temp[len] == '\0');
257 std::string log(temp.get(), len);
258 set_log_info(ProcessLogInfo(log).c_str());
261 void Program::ClearUniforms(
262 std::vector<uint8>* zero_buffer) {
264 if (uniforms_cleared_) {
267 uniforms_cleared_ = true;
268 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
269 const UniformInfo& uniform_info = uniform_infos_[ii];
270 if (!uniform_info.IsValid()) {
273 GLint location = uniform_info.element_locations[0];
274 GLsizei size = uniform_info.size;
275 uint32 unit_size = GLES2Util::GetGLDataTypeSizeForUniforms(
277 uint32 size_needed = size * unit_size;
278 if (size_needed > zero_buffer->size()) {
279 zero_buffer->resize(size_needed, 0u);
281 const void* zero = &(*zero_buffer)[0];
282 switch (uniform_info.type) {
284 glUniform1fv(location, size, reinterpret_cast<const GLfloat*>(zero));
287 glUniform2fv(location, size, reinterpret_cast<const GLfloat*>(zero));
290 glUniform3fv(location, size, reinterpret_cast<const GLfloat*>(zero));
293 glUniform4fv(location, size, reinterpret_cast<const GLfloat*>(zero));
298 case GL_SAMPLER_CUBE:
299 case GL_SAMPLER_EXTERNAL_OES:
300 case GL_SAMPLER_3D_OES:
301 case GL_SAMPLER_2D_RECT_ARB:
302 glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero));
306 glUniform2iv(location, size, reinterpret_cast<const GLint*>(zero));
310 glUniform3iv(location, size, reinterpret_cast<const GLint*>(zero));
314 glUniform4iv(location, size, reinterpret_cast<const GLint*>(zero));
318 location, size, false, reinterpret_cast<const GLfloat*>(zero));
322 location, size, false, reinterpret_cast<const GLfloat*>(zero));
326 location, size, false, reinterpret_cast<const GLfloat*>(zero));
338 UniformData() : size(-1), type(GL_NONE), location(0), added(false) {
340 std::string queried_name;
341 std::string corrected_name;
342 std::string original_name;
349 struct UniformDataComparer {
350 bool operator()(const UniformData& lhs, const UniformData& rhs) const {
351 return lhs.queried_name < rhs.queried_name;
355 } // anonymous namespace
357 void Program::Update() {
361 uniforms_cleared_ = false;
362 GLint num_attribs = 0;
364 GLint max_location = -1;
365 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs);
366 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
367 // TODO(gman): Should we check for error?
368 scoped_ptr<char[]> name_buffer(new char[max_len]);
369 for (GLint ii = 0; ii < num_attribs; ++ii) {
374 service_id_, ii, max_len, &length, &size, &type, name_buffer.get());
375 DCHECK(max_len == 0 || length < max_len);
376 DCHECK(length == 0 || name_buffer[length] == '\0');
377 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
378 std::string original_name;
379 GetVertexAttribData(name_buffer.get(), &original_name, &type);
380 // TODO(gman): Should we check for error?
381 GLint location = glGetAttribLocation(service_id_, name_buffer.get());
382 if (location > max_location) {
383 max_location = location;
385 attrib_infos_.push_back(
386 VertexAttrib(1, type, original_name, location));
387 max_attrib_name_length_ = std::max(
388 max_attrib_name_length_, static_cast<GLsizei>(original_name.size()));
392 // Create attrib location to index map.
393 attrib_location_to_index_map_.resize(max_location + 1);
394 for (GLint ii = 0; ii <= max_location; ++ii) {
395 attrib_location_to_index_map_[ii] = -1;
397 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
398 const VertexAttrib& info = attrib_infos_[ii];
399 attrib_location_to_index_map_[info.location] = ii;
403 if (CommandLine::ForCurrentProcess()->HasSwitch(
404 switches::kEnableGPUServiceLoggingGPU)) {
405 DVLOG(1) << "----: attribs for service_id: " << service_id();
406 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
407 const VertexAttrib& info = attrib_infos_[ii];
408 DVLOG(1) << ii << ": loc = " << info.location
409 << ", size = " << info.size
410 << ", type = " << GLES2Util::GetStringEnum(info.type)
411 << ", name = " << info.name;
417 GLint num_uniforms = 0;
418 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
419 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
420 name_buffer.reset(new char[max_len]);
422 // Reads all the names.
423 std::vector<UniformData> uniform_data;
424 for (GLint ii = 0; ii < num_uniforms; ++ii) {
428 service_id_, ii, max_len, &length,
429 &data.size, &data.type, name_buffer.get());
430 DCHECK(max_len == 0 || length < max_len);
431 DCHECK(length == 0 || name_buffer[length] == '\0');
432 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
433 data.queried_name = std::string(name_buffer.get());
434 GetCorrectedUniformData(
436 &data.corrected_name, &data.original_name, &data.size, &data.type);
437 uniform_data.push_back(data);
441 // NOTE: We don't care if 2 uniforms are bound to the same location.
442 // One of them will take preference. The spec allows this, same as
443 // BindAttribLocation.
445 // The reason we don't check is if we were to fail we'd have to
446 // restore the previous program but since we've already linked successfully
447 // at this point the previous program is gone.
449 // Assigns the uniforms with bindings.
450 size_t next_available_index = 0;
451 for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
452 UniformData& data = uniform_data[ii];
453 data.location = glGetUniformLocation(
454 service_id_, data.queried_name.c_str());
456 std::string short_name;
457 int element_index = 0;
458 bool good = GetUniformNameSansElement(data.queried_name, &element_index,
461 LocationMap::const_iterator it = bind_uniform_location_map_.find(
463 if (it != bind_uniform_location_map_.end()) {
464 data.added = AddUniformInfo(
465 data.size, data.type, data.location, it->second, data.corrected_name,
466 data.original_name, &next_available_index);
470 // Assigns the uniforms that were not bound.
471 for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
472 const UniformData& data = uniform_data[ii];
475 data.size, data.type, data.location, -1, data.corrected_name,
476 data.original_name, &next_available_index);
481 if (CommandLine::ForCurrentProcess()->HasSwitch(
482 switches::kEnableGPUServiceLoggingGPU)) {
483 DVLOG(1) << "----: uniforms for service_id: " << service_id();
484 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
485 const UniformInfo& info = uniform_infos_[ii];
486 if (info.IsValid()) {
487 DVLOG(1) << ii << ": loc = " << info.element_locations[0]
488 << ", size = " << info.size
489 << ", type = " << GLES2Util::GetStringEnum(info.type)
490 << ", name = " << info.name;
499 void Program::ExecuteBindAttribLocationCalls() {
500 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
501 it != bind_attrib_location_map_.end(); ++it) {
502 const std::string* mapped_name = GetAttribMappedName(it->first);
504 glBindAttribLocation(service_id_, it->second, mapped_name->c_str());
508 bool Program::Link(ShaderManager* manager,
509 ShaderTranslator* vertex_translator,
510 ShaderTranslator* fragment_translator,
511 Program::VaryingsPackingOption varyings_packing_option,
512 const ShaderCacheCallback& shader_callback) {
515 set_log_info("missing shaders");
518 if (DetectAttribLocationBindingConflicts()) {
519 set_log_info("glBindAttribLocation() conflicts");
522 std::string conflicting_name;
523 if (DetectUniformsMismatch(&conflicting_name)) {
524 std::string info_log = "Uniforms with the same name but different "
525 "type/precision: " + conflicting_name;
526 set_log_info(ProcessLogInfo(info_log).c_str());
529 if (DetectVaryingsMismatch(&conflicting_name)) {
530 std::string info_log = "Varyings with the same name but different type, "
531 "or statically used varyings in fragment shader are "
532 "not declared in vertex shader: " + conflicting_name;
533 set_log_info(ProcessLogInfo(info_log).c_str());
536 if (DetectBuiltInInvariantConflicts()) {
537 set_log_info("Invariant settings for certain built-in varyings "
541 if (DetectGlobalNameConflicts(&conflicting_name)) {
542 std::string info_log = "Name conflicts between an uniform and an "
543 "attribute: " + conflicting_name;
544 set_log_info(ProcessLogInfo(info_log).c_str());
547 if (!CheckVaryingsPacking(varyings_packing_option)) {
548 set_log_info("Varyings over maximum register limit");
552 TimeTicks before_time = TimeTicks::HighResNow();
554 ProgramCache* cache = manager_->program_cache_;
556 DCHECK(!attached_shaders_[0]->signature_source().empty() &&
557 !attached_shaders_[1]->signature_source().empty());
558 ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
559 attached_shaders_[0]->signature_source(),
561 attached_shaders_[1]->signature_source(),
563 &bind_attrib_location_map_);
565 if (status == ProgramCache::LINK_SUCCEEDED) {
566 ProgramCache::ProgramLoadResult success =
567 cache->LoadLinkedProgram(service_id(),
568 attached_shaders_[0].get(),
570 attached_shaders_[1].get(),
572 &bind_attrib_location_map_,
574 link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
575 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
580 ExecuteBindAttribLocationCalls();
581 before_time = TimeTicks::HighResNow();
582 if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
583 glProgramParameteri(service_id(),
584 PROGRAM_BINARY_RETRIEVABLE_HINT,
587 glLinkProgram(service_id());
591 glGetProgramiv(service_id(), GL_LINK_STATUS, &success);
592 if (success == GL_TRUE) {
596 cache->SaveLinkedProgram(service_id(),
597 attached_shaders_[0].get(),
599 attached_shaders_[1].get(),
601 &bind_attrib_location_map_,
604 UMA_HISTOGRAM_CUSTOM_COUNTS(
605 "GPU.ProgramCache.BinaryCacheMissTime",
606 static_cast<base::HistogramBase::Sample>(
607 (TimeTicks::HighResNow() - before_time).InMicroseconds()),
609 static_cast<base::HistogramBase::Sample>(
610 TimeDelta::FromSeconds(10).InMicroseconds()),
613 UMA_HISTOGRAM_CUSTOM_COUNTS(
614 "GPU.ProgramCache.BinaryCacheHitTime",
615 static_cast<base::HistogramBase::Sample>(
616 (TimeTicks::HighResNow() - before_time).InMicroseconds()),
618 static_cast<base::HistogramBase::Sample>(
619 TimeDelta::FromSeconds(1).InMicroseconds()),
625 return success == GL_TRUE;
628 void Program::Validate() {
630 set_log_info("program not linked");
633 glValidateProgram(service_id());
637 GLint Program::GetUniformFakeLocation(
638 const std::string& name) const {
639 bool getting_array_location = false;
640 size_t open_pos = std::string::npos;
642 if (!GLES2Util::ParseUniformName(
643 name, &open_pos, &index, &getting_array_location)) {
646 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
647 const UniformInfo& info = uniform_infos_[ii];
648 if (!info.IsValid()) {
651 if (info.name == name ||
653 info.name.compare(0, info.name.size() - 3, name) == 0)) {
654 return info.fake_location_base;
655 } else if (getting_array_location && info.is_array) {
656 // Look for an array specification.
657 size_t open_pos_2 = info.name.find_last_of('[');
658 if (open_pos_2 == open_pos &&
659 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
660 if (index >= 0 && index < info.size) {
661 DCHECK_GT(static_cast<int>(info.element_locations.size()), index);
662 if (info.element_locations[index] == -1)
664 return ProgramManager::MakeFakeLocation(
665 info.fake_location_base, index);
673 GLint Program::GetAttribLocation(
674 const std::string& original_name) const {
675 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
676 const VertexAttrib& info = attrib_infos_[ii];
677 if (info.name == original_name) {
678 return info.location;
684 const Program::UniformInfo*
685 Program::GetUniformInfoByFakeLocation(
686 GLint fake_location, GLint* real_location, GLint* array_index) const {
687 DCHECK(real_location);
689 if (fake_location < 0) {
693 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
694 if (uniform_index >= 0 &&
695 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
696 const UniformInfo& uniform_info = uniform_infos_[uniform_index];
697 if (!uniform_info.IsValid()) {
700 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
701 if (element_index < uniform_info.size) {
702 *real_location = uniform_info.element_locations[element_index];
703 *array_index = element_index;
704 return &uniform_info;
710 const std::string* Program::GetAttribMappedName(
711 const std::string& original_name) const {
712 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
713 Shader* shader = attached_shaders_[ii].get();
715 const std::string* mapped_name =
716 shader->GetAttribMappedName(original_name);
724 const std::string* Program::GetOriginalNameFromHashedName(
725 const std::string& hashed_name) const {
726 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
727 Shader* shader = attached_shaders_[ii].get();
729 const std::string* original_name =
730 shader->GetOriginalNameFromHashedName(hashed_name);
732 return original_name;
738 bool Program::SetUniformLocationBinding(
739 const std::string& name, GLint location) {
740 std::string short_name;
741 int element_index = 0;
742 if (!GetUniformNameSansElement(name, &element_index, &short_name) ||
743 element_index != 0) {
747 bind_uniform_location_map_[short_name] = location;
751 // Note: This is only valid to call right after a program has been linked
753 void Program::GetCorrectedUniformData(
754 const std::string& name,
755 std::string* corrected_name, std::string* original_name,
756 GLsizei* size, GLenum* type) const {
757 DCHECK(corrected_name && original_name && size && type);
758 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
759 Shader* shader = attached_shaders_[ii].get();
762 const sh::ShaderVariable* info = NULL;
763 const sh::Uniform* uniform = shader->GetUniformInfo(name);
766 found = uniform->findInfoByMappedName(name, &info, original_name);
768 const std::string kArraySpec("[0]");
769 if (info->arraySize > 0 && !EndsWith(name, kArraySpec, true)) {
770 *corrected_name = name + kArraySpec;
771 *original_name += kArraySpec;
773 *corrected_name = name;
776 *size = std::max(1u, info->arraySize);
780 // TODO(zmo): this path should never be reached unless there is a serious
781 // bug in the driver or in ANGLE translator.
782 *corrected_name = name;
783 *original_name = name;
786 void Program::GetVertexAttribData(
787 const std::string& name, std::string* original_name, GLenum* type) const {
788 DCHECK(original_name);
790 Shader* shader = attached_shaders_[ShaderTypeToIndex(GL_VERTEX_SHADER)].get();
792 // Vertex attributes can not be arrays or structs (GLSL ES 3.00.4, section
793 // 4.3.4, "Input Variables"), so the top level sh::Attribute returns the
794 // information we need.
795 const sh::Attribute* info = shader->GetAttribInfo(name);
797 *original_name = info->name;
802 // TODO(zmo): this path should never be reached unless there is a serious
803 // bug in the driver or in ANGLE translator.
804 *original_name = name;
807 bool Program::AddUniformInfo(
808 GLsizei size, GLenum type, GLint location, GLint fake_base_location,
809 const std::string& name, const std::string& original_name,
810 size_t* next_available_index) {
811 DCHECK(next_available_index);
812 const char* kArraySpec = "[0]";
813 size_t uniform_index =
814 fake_base_location >= 0 ? fake_base_location : *next_available_index;
815 if (uniform_infos_.size() < uniform_index + 1) {
816 uniform_infos_.resize(uniform_index + 1);
819 // return if this location is already in use.
820 if (uniform_infos_[uniform_index].IsValid()) {
821 DCHECK_GE(fake_base_location, 0);
825 uniform_infos_[uniform_index] = UniformInfo(
826 size, type, uniform_index, original_name);
829 UniformInfo& info = uniform_infos_[uniform_index];
830 info.element_locations.resize(size);
831 info.element_locations[0] = location;
833 size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
834 info.texture_units.clear();
835 info.texture_units.resize(num_texture_units, 0);
838 // Go through the array element locations looking for a match.
839 // We can skip the first element because it's the same as the
840 // the location without the array operators.
841 size_t array_pos = name.rfind(kArraySpec);
842 std::string base_name = name;
843 if (name.size() > 3) {
844 if (array_pos != name.size() - 3) {
845 info.name = name + kArraySpec;
847 base_name = name.substr(0, name.size() - 3);
850 for (GLsizei ii = 1; ii < info.size; ++ii) {
851 std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
852 info.element_locations[ii] =
853 glGetUniformLocation(service_id_, element_name.c_str());
859 (info.name.size() > 3 &&
860 info.name.rfind(kArraySpec) == info.name.size() - 3));
862 if (info.IsSampler()) {
863 sampler_indices_.push_back(info.fake_location_base);
865 max_uniform_name_length_ =
866 std::max(max_uniform_name_length_,
867 static_cast<GLsizei>(info.name.size()));
869 while (*next_available_index < uniform_infos_.size() &&
870 uniform_infos_[*next_available_index].IsValid()) {
871 *next_available_index = *next_available_index + 1;
877 const Program::UniformInfo*
878 Program::GetUniformInfo(
880 if (static_cast<size_t>(index) >= uniform_infos_.size()) {
884 const UniformInfo& info = uniform_infos_[index];
885 return info.IsValid() ? &info : NULL;
888 bool Program::SetSamplers(
889 GLint num_texture_units, GLint fake_location,
890 GLsizei count, const GLint* value) {
891 if (fake_location < 0) {
894 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
895 if (uniform_index >= 0 &&
896 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
897 UniformInfo& info = uniform_infos_[uniform_index];
898 if (!info.IsValid()) {
901 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
902 if (element_index < info.size) {
903 count = std::min(info.size - element_index, count);
904 if (info.IsSampler() && count > 0) {
905 for (GLsizei ii = 0; ii < count; ++ii) {
906 if (value[ii] < 0 || value[ii] >= num_texture_units) {
910 std::copy(value, value + count,
911 info.texture_units.begin() + element_index);
919 void Program::GetProgramiv(GLenum pname, GLint* params) {
921 case GL_ACTIVE_ATTRIBUTES:
922 *params = attrib_infos_.size();
924 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
925 // Notice +1 to accomodate NULL terminator.
926 *params = max_attrib_name_length_ + 1;
928 case GL_ACTIVE_UNIFORMS:
929 *params = num_uniforms_;
931 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
932 // Notice +1 to accomodate NULL terminator.
933 *params = max_uniform_name_length_ + 1;
936 *params = link_status_;
938 case GL_INFO_LOG_LENGTH:
939 // Notice +1 to accomodate NULL terminator.
940 *params = log_info_.get() ? (log_info_->size() + 1) : 0;
942 case GL_DELETE_STATUS:
945 case GL_VALIDATE_STATUS:
949 glGetProgramiv(service_id_, pname, params);
953 glGetProgramiv(service_id_, pname, params);
958 bool Program::AttachShader(
959 ShaderManager* shader_manager,
961 DCHECK(shader_manager);
963 int index = ShaderTypeToIndex(shader->shader_type());
964 if (attached_shaders_[index].get() != NULL) {
967 attached_shaders_[index] = scoped_refptr<Shader>(shader);
968 shader_manager->UseShader(shader);
972 bool Program::DetachShader(
973 ShaderManager* shader_manager,
975 DCHECK(shader_manager);
977 if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() !=
981 attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL;
982 shader_manager->UnuseShader(shader);
986 void Program::DetachShaders(ShaderManager* shader_manager) {
987 DCHECK(shader_manager);
988 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
989 if (attached_shaders_[ii].get()) {
990 DetachShader(shader_manager, attached_shaders_[ii].get());
995 bool Program::CanLink() const {
996 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
997 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid()) {
1004 bool Program::DetectAttribLocationBindingConflicts() const {
1005 std::set<GLint> location_binding_used;
1006 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
1007 it != bind_attrib_location_map_.end(); ++it) {
1008 // Find out if an attribute is statically used in this program's shaders.
1009 const sh::Attribute* attrib = NULL;
1010 const std::string* mapped_name = GetAttribMappedName(it->first);
1013 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1014 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid())
1016 attrib = attached_shaders_[ii]->GetAttribInfo(*mapped_name);
1018 if (attrib->staticUse)
1025 size_t num_of_locations = 1;
1026 switch (attrib->type) {
1028 num_of_locations = 2;
1031 num_of_locations = 3;
1034 num_of_locations = 4;
1039 for (size_t ii = 0; ii < num_of_locations; ++ii) {
1040 GLint loc = it->second + ii;
1041 std::pair<std::set<GLint>::iterator, bool> result =
1042 location_binding_used.insert(loc);
1051 bool Program::DetectUniformsMismatch(std::string* conflicting_name) const {
1052 typedef std::map<std::string, const sh::Uniform*> UniformPointerMap;
1053 UniformPointerMap uniform_pointer_map;
1054 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1055 const UniformMap& shader_uniforms = attached_shaders_[ii]->uniform_map();
1056 for (UniformMap::const_iterator iter = shader_uniforms.begin();
1057 iter != shader_uniforms.end(); ++iter) {
1058 const std::string& name = iter->first;
1059 UniformPointerMap::iterator hit = uniform_pointer_map.find(name);
1060 if (hit == uniform_pointer_map.end()) {
1061 uniform_pointer_map[name] = &(iter->second);
1063 // If a uniform is in the map, i.e., it has already been declared by
1064 // another shader, then the type, precision, etc. must match.
1065 if (hit->second->isSameUniformAtLinkTime(iter->second))
1067 *conflicting_name = name;
1075 bool Program::DetectVaryingsMismatch(std::string* conflicting_name) const {
1076 DCHECK(attached_shaders_[0].get() &&
1077 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1078 attached_shaders_[1].get() &&
1079 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1080 const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
1081 const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
1083 for (VaryingMap::const_iterator iter = fragment_varyings->begin();
1084 iter != fragment_varyings->end(); ++iter) {
1085 const std::string& name = iter->first;
1086 if (IsBuiltInFragmentVarying(name))
1089 VaryingMap::const_iterator hit = vertex_varyings->find(name);
1090 if (hit == vertex_varyings->end()) {
1091 if (iter->second.staticUse) {
1092 *conflicting_name = name;
1098 if (!hit->second.isSameVaryingAtLinkTime(iter->second)) {
1099 *conflicting_name = name;
1107 bool Program::DetectBuiltInInvariantConflicts() const {
1108 DCHECK(attached_shaders_[0].get() &&
1109 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1110 attached_shaders_[1].get() &&
1111 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1112 const VaryingMap& vertex_varyings = attached_shaders_[0]->varying_map();
1113 const VaryingMap& fragment_varyings = attached_shaders_[1]->varying_map();
1115 bool gl_position_invariant = IsBuiltInInvariant(
1116 vertex_varyings, "gl_Position");
1117 bool gl_point_size_invariant = IsBuiltInInvariant(
1118 vertex_varyings, "gl_PointSize");
1120 bool gl_frag_coord_invariant = IsBuiltInInvariant(
1121 fragment_varyings, "gl_FragCoord");
1122 bool gl_point_coord_invariant = IsBuiltInInvariant(
1123 fragment_varyings, "gl_PointCoord");
1125 return ((gl_frag_coord_invariant && !gl_position_invariant) ||
1126 (gl_point_coord_invariant && !gl_point_size_invariant));
1129 bool Program::DetectGlobalNameConflicts(std::string* conflicting_name) const {
1130 DCHECK(attached_shaders_[0].get() &&
1131 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1132 attached_shaders_[1].get() &&
1133 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1134 const UniformMap* uniforms[2];
1135 uniforms[0] = &(attached_shaders_[0]->uniform_map());
1136 uniforms[1] = &(attached_shaders_[1]->uniform_map());
1137 const AttributeMap* attribs =
1138 &(attached_shaders_[0]->attrib_map());
1140 for (AttributeMap::const_iterator iter = attribs->begin();
1141 iter != attribs->end(); ++iter) {
1142 for (int ii = 0; ii < 2; ++ii) {
1143 if (uniforms[ii]->find(iter->first) != uniforms[ii]->end()) {
1144 *conflicting_name = iter->first;
1152 bool Program::CheckVaryingsPacking(
1153 Program::VaryingsPackingOption option) const {
1154 DCHECK(attached_shaders_[0].get() &&
1155 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1156 attached_shaders_[1].get() &&
1157 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1158 const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
1159 const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
1161 std::map<std::string, ShVariableInfo> combined_map;
1163 for (VaryingMap::const_iterator iter = fragment_varyings->begin();
1164 iter != fragment_varyings->end(); ++iter) {
1165 if (!iter->second.staticUse && option == kCountOnlyStaticallyUsed)
1167 if (!IsBuiltInFragmentVarying(iter->first)) {
1168 VaryingMap::const_iterator vertex_iter =
1169 vertex_varyings->find(iter->first);
1170 if (vertex_iter == vertex_varyings->end() ||
1171 (!vertex_iter->second.staticUse &&
1172 option == kCountOnlyStaticallyUsed))
1177 var.type = static_cast<sh::GLenum>(iter->second.type);
1178 var.size = std::max(1u, iter->second.arraySize);
1179 combined_map[iter->first] = var;
1182 if (combined_map.size() == 0)
1184 scoped_ptr<ShVariableInfo[]> variables(
1185 new ShVariableInfo[combined_map.size()]);
1187 for (std::map<std::string, ShVariableInfo>::const_iterator iter =
1188 combined_map.begin();
1189 iter != combined_map.end(); ++iter) {
1190 variables[index].type = iter->second.type;
1191 variables[index].size = iter->second.size;
1194 return ShCheckVariablesWithinPackingLimits(
1195 static_cast<int>(manager_->max_varying_vectors()),
1197 combined_map.size());
1200 static uint32 ComputeOffset(const void* start, const void* position) {
1201 return static_cast<const uint8*>(position) -
1202 static_cast<const uint8*>(start);
1205 void Program::GetProgramInfo(
1206 ProgramManager* manager, CommonDecoder::Bucket* bucket) const {
1207 // NOTE: It seems to me the math in here does not need check for overflow
1208 // because the data being calucated from has various small limits. The max
1209 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1210 // of an identifier is 256 characters.
1211 uint32 num_locations = 0;
1212 uint32 total_string_size = 0;
1214 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1215 const VertexAttrib& info = attrib_infos_[ii];
1217 total_string_size += info.name.size();
1220 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1221 const UniformInfo& info = uniform_infos_[ii];
1222 if (info.IsValid()) {
1223 num_locations += info.element_locations.size();
1224 total_string_size += info.name.size();
1228 uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
1229 uint32 input_size = num_inputs * sizeof(ProgramInput);
1230 uint32 location_size = num_locations * sizeof(int32);
1231 uint32 size = sizeof(ProgramInfoHeader) +
1232 input_size + location_size + total_string_size;
1234 bucket->SetSize(size);
1235 ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
1236 ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
1237 sizeof(ProgramInfoHeader), input_size);
1238 int32* locations = bucket->GetDataAs<int32*>(
1239 sizeof(ProgramInfoHeader) + input_size, location_size);
1240 char* strings = bucket->GetDataAs<char*>(
1241 sizeof(ProgramInfoHeader) + input_size + location_size,
1248 header->link_status = link_status_;
1249 header->num_attribs = attrib_infos_.size();
1250 header->num_uniforms = num_uniforms_;
1252 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1253 const VertexAttrib& info = attrib_infos_[ii];
1254 inputs->size = info.size;
1255 inputs->type = info.type;
1256 inputs->location_offset = ComputeOffset(header, locations);
1257 inputs->name_offset = ComputeOffset(header, strings);
1258 inputs->name_length = info.name.size();
1259 *locations++ = info.location;
1260 memcpy(strings, info.name.c_str(), info.name.size());
1261 strings += info.name.size();
1265 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1266 const UniformInfo& info = uniform_infos_[ii];
1267 if (info.IsValid()) {
1268 inputs->size = info.size;
1269 inputs->type = info.type;
1270 inputs->location_offset = ComputeOffset(header, locations);
1271 inputs->name_offset = ComputeOffset(header, strings);
1272 inputs->name_length = info.name.size();
1273 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
1274 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
1275 if (info.element_locations[jj] == -1)
1278 *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
1280 memcpy(strings, info.name.c_str(), info.name.size());
1281 strings += info.name.size();
1286 DCHECK_EQ(ComputeOffset(header, strings), size);
1289 Program::~Program() {
1291 if (manager_->have_context_) {
1292 glDeleteProgram(service_id());
1294 manager_->StopTracking(this);
1300 ProgramManager::ProgramManager(ProgramCache* program_cache,
1301 uint32 max_varying_vectors)
1302 : program_count_(0),
1303 have_context_(true),
1304 program_cache_(program_cache),
1305 max_varying_vectors_(max_varying_vectors) { }
1307 ProgramManager::~ProgramManager() {
1308 DCHECK(programs_.empty());
1311 void ProgramManager::Destroy(bool have_context) {
1312 have_context_ = have_context;
1316 void ProgramManager::StartTracking(Program* /* program */) {
1320 void ProgramManager::StopTracking(Program* /* program */) {
1324 Program* ProgramManager::CreateProgram(
1325 GLuint client_id, GLuint service_id) {
1326 std::pair<ProgramMap::iterator, bool> result =
1328 std::make_pair(client_id,
1329 scoped_refptr<Program>(
1330 new Program(this, service_id))));
1331 DCHECK(result.second);
1332 return result.first->second.get();
1335 Program* ProgramManager::GetProgram(GLuint client_id) {
1336 ProgramMap::iterator it = programs_.find(client_id);
1337 return it != programs_.end() ? it->second.get() : NULL;
1340 bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
1341 // This doesn't need to be fast. It's only used during slow queries.
1342 for (ProgramMap::const_iterator it = programs_.begin();
1343 it != programs_.end(); ++it) {
1344 if (it->second->service_id() == service_id) {
1345 *client_id = it->first;
1352 ProgramCache* ProgramManager::program_cache() const {
1353 return program_cache_;
1356 bool ProgramManager::IsOwned(Program* program) {
1357 for (ProgramMap::iterator it = programs_.begin();
1358 it != programs_.end(); ++it) {
1359 if (it->second.get() == program) {
1366 void ProgramManager::RemoveProgramInfoIfUnused(
1367 ShaderManager* shader_manager, Program* program) {
1368 DCHECK(shader_manager);
1370 DCHECK(IsOwned(program));
1371 if (program->IsDeleted() && !program->InUse()) {
1372 program->DetachShaders(shader_manager);
1373 for (ProgramMap::iterator it = programs_.begin();
1374 it != programs_.end(); ++it) {
1375 if (it->second.get() == program) {
1376 programs_.erase(it);
1384 void ProgramManager::MarkAsDeleted(
1385 ShaderManager* shader_manager,
1387 DCHECK(shader_manager);
1389 DCHECK(IsOwned(program));
1390 program->MarkAsDeleted();
1391 RemoveProgramInfoIfUnused(shader_manager, program);
1394 void ProgramManager::UseProgram(Program* program) {
1396 DCHECK(IsOwned(program));
1397 program->IncUseCount();
1400 void ProgramManager::UnuseProgram(
1401 ShaderManager* shader_manager,
1403 DCHECK(shader_manager);
1405 DCHECK(IsOwned(program));
1406 program->DecUseCount();
1407 RemoveProgramInfoIfUnused(shader_manager, program);
1410 void ProgramManager::ClearUniforms(Program* program) {
1412 program->ClearUniforms(&zero_);
1415 int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
1416 return index + element * 0x10000;
1419 } // namespace gles2