Home | History | Annotate | Download | only in service
      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.
      4 
      5 #include "gpu/command_buffer/service/program_manager.h"
      6 
      7 #include <algorithm>
      8 #include <set>
      9 #include <utility>
     10 #include <vector>
     11 
     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"
     28 
     29 using base::TimeDelta;
     30 using base::TimeTicks;
     31 
     32 namespace gpu {
     33 namespace gles2 {
     34 
     35 namespace {
     36 
     37 int ShaderTypeToIndex(GLenum shader_type) {
     38   switch (shader_type) {
     39     case GL_VERTEX_SHADER:
     40       return 0;
     41     case GL_FRAGMENT_SHADER:
     42       return 1;
     43     default:
     44       NOTREACHED();
     45       return 0;
     46   }
     47 }
     48 
     49 ShaderTranslator* ShaderIndexToTranslator(
     50     int index,
     51     ShaderTranslator* vertex_translator,
     52     ShaderTranslator* fragment_translator) {
     53   switch (index) {
     54     case 0:
     55       return vertex_translator;
     56     case 1:
     57       return fragment_translator;
     58     default:
     59       NOTREACHED();
     60       return NULL;
     61   }
     62 }
     63 
     64 // Given a name like "foo.bar[123].moo[456]" sets new_name to "foo.bar[123].moo"
     65 // and sets element_index to 456. returns false if element expression was not a
     66 // whole decimal number. For example: "foo[1b2]"
     67 bool GetUniformNameSansElement(
     68     const std::string& name, int* element_index, std::string* new_name) {
     69   DCHECK(element_index);
     70   DCHECK(new_name);
     71   if (name.size() < 3 || name[name.size() - 1] != ']') {
     72     *element_index = 0;
     73     *new_name = name;
     74     return true;
     75   }
     76 
     77   // Look for an array specification.
     78   size_t open_pos = name.find_last_of('[');
     79   if (open_pos == std::string::npos ||
     80       open_pos >= name.size() - 2) {
     81     return false;
     82   }
     83 
     84   GLint index = 0;
     85   size_t last = name.size() - 1;
     86   for (size_t pos = open_pos + 1; pos < last; ++pos) {
     87     int8 digit = name[pos] - '0';
     88     if (digit < 0 || digit > 9) {
     89       return false;
     90     }
     91     index = index * 10 + digit;
     92   }
     93 
     94   *element_index = index;
     95   *new_name = name.substr(0, open_pos);
     96   return true;
     97 }
     98 
     99 }  // anonymous namespace.
    100 
    101 Program::UniformInfo::UniformInfo()
    102     : size(0),
    103       type(GL_NONE),
    104       fake_location_base(0),
    105       is_array(false) {
    106 }
    107 
    108 Program::UniformInfo::UniformInfo(
    109     GLsizei _size,
    110     GLenum _type,
    111     int _fake_location_base,
    112     const std::string& _name)
    113     : size(_size),
    114       type(_type),
    115       fake_location_base(_fake_location_base),
    116       is_array(false),
    117       name(_name) {
    118 }
    119 
    120 Program::UniformInfo::~UniformInfo() {}
    121 
    122 bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
    123   static const char kInvalidPrefix[] = { 'g', 'l', '_' };
    124   return (length >= sizeof(kInvalidPrefix) &&
    125       memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
    126 }
    127 
    128 Program::Program(
    129     ProgramManager* manager, GLuint service_id)
    130     : manager_(manager),
    131       use_count_(0),
    132       max_attrib_name_length_(0),
    133       max_uniform_name_length_(0),
    134       service_id_(service_id),
    135       deleted_(false),
    136       valid_(false),
    137       link_status_(false),
    138       uniforms_cleared_(false),
    139       num_uniforms_(0) {
    140   manager_->StartTracking(this);
    141 }
    142 
    143 void Program::Reset() {
    144   valid_ = false;
    145   link_status_ = false;
    146   num_uniforms_ = 0;
    147   max_uniform_name_length_ = 0;
    148   max_attrib_name_length_ = 0;
    149   attrib_infos_.clear();
    150   uniform_infos_.clear();
    151   sampler_indices_.clear();
    152   attrib_location_to_index_map_.clear();
    153 }
    154 
    155 std::string Program::ProcessLogInfo(
    156     const std::string& log) {
    157   std::string output;
    158   re2::StringPiece input(log);
    159   std::string prior_log;
    160   std::string hashed_name;
    161   while (RE2::Consume(&input,
    162                       "(.*)(webgl_[0123456789abcdefABCDEF]+)",
    163                       &prior_log,
    164                       &hashed_name)) {
    165     output += prior_log;
    166 
    167     const std::string* original_name =
    168         GetOriginalNameFromHashedName(hashed_name);
    169     if (original_name)
    170       output += *original_name;
    171     else
    172       output += hashed_name;
    173   }
    174 
    175   return output + input.as_string();
    176 }
    177 
    178 void Program::UpdateLogInfo() {
    179   GLint max_len = 0;
    180   glGetProgramiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
    181   if (max_len == 0) {
    182     set_log_info(NULL);
    183     return;
    184   }
    185   scoped_ptr<char[]> temp(new char[max_len]);
    186   GLint len = 0;
    187   glGetProgramInfoLog(service_id_, max_len, &len, temp.get());
    188   DCHECK(max_len == 0 || len < max_len);
    189   DCHECK(len == 0 || temp[len] == '\0');
    190   std::string log(temp.get(), len);
    191   set_log_info(ProcessLogInfo(log).c_str());
    192 }
    193 
    194 void Program::ClearUniforms(
    195     std::vector<uint8>* zero_buffer) {
    196   DCHECK(zero_buffer);
    197   if (uniforms_cleared_) {
    198     return;
    199   }
    200   uniforms_cleared_ = true;
    201   for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
    202     const UniformInfo& uniform_info = uniform_infos_[ii];
    203     if (!uniform_info.IsValid()) {
    204       continue;
    205     }
    206     GLint location = uniform_info.element_locations[0];
    207     GLsizei size = uniform_info.size;
    208     uint32 unit_size =  GLES2Util::GetGLDataTypeSizeForUniforms(
    209         uniform_info.type);
    210     uint32 size_needed = size * unit_size;
    211     if (size_needed > zero_buffer->size()) {
    212       zero_buffer->resize(size_needed, 0u);
    213     }
    214     const void* zero = &(*zero_buffer)[0];
    215     switch (uniform_info.type) {
    216     case GL_FLOAT:
    217       glUniform1fv(location, size, reinterpret_cast<const GLfloat*>(zero));
    218       break;
    219     case GL_FLOAT_VEC2:
    220       glUniform2fv(location, size, reinterpret_cast<const GLfloat*>(zero));
    221       break;
    222     case GL_FLOAT_VEC3:
    223       glUniform3fv(location, size, reinterpret_cast<const GLfloat*>(zero));
    224       break;
    225     case GL_FLOAT_VEC4:
    226       glUniform4fv(location, size, reinterpret_cast<const GLfloat*>(zero));
    227       break;
    228     case GL_INT:
    229     case GL_BOOL:
    230     case GL_SAMPLER_2D:
    231     case GL_SAMPLER_CUBE:
    232     case GL_SAMPLER_EXTERNAL_OES:
    233     case GL_SAMPLER_3D_OES:
    234     case GL_SAMPLER_2D_RECT_ARB:
    235       glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero));
    236       break;
    237     case GL_INT_VEC2:
    238     case GL_BOOL_VEC2:
    239       glUniform2iv(location, size, reinterpret_cast<const GLint*>(zero));
    240       break;
    241     case GL_INT_VEC3:
    242     case GL_BOOL_VEC3:
    243       glUniform3iv(location, size, reinterpret_cast<const GLint*>(zero));
    244       break;
    245     case GL_INT_VEC4:
    246     case GL_BOOL_VEC4:
    247       glUniform4iv(location, size, reinterpret_cast<const GLint*>(zero));
    248       break;
    249     case GL_FLOAT_MAT2:
    250       glUniformMatrix2fv(
    251           location, size, false, reinterpret_cast<const GLfloat*>(zero));
    252       break;
    253     case GL_FLOAT_MAT3:
    254       glUniformMatrix3fv(
    255           location, size, false, reinterpret_cast<const GLfloat*>(zero));
    256       break;
    257     case GL_FLOAT_MAT4:
    258       glUniformMatrix4fv(
    259           location, size, false, reinterpret_cast<const GLfloat*>(zero));
    260       break;
    261     default:
    262       NOTREACHED();
    263       break;
    264     }
    265   }
    266 }
    267 
    268 namespace {
    269 
    270 struct UniformData {
    271   UniformData() : size(-1), type(GL_NONE), location(0), added(false) {
    272   }
    273   std::string queried_name;
    274   std::string corrected_name;
    275   std::string original_name;
    276   GLsizei size;
    277   GLenum type;
    278   GLint location;
    279   bool added;
    280 };
    281 
    282 struct UniformDataComparer {
    283   bool operator()(const UniformData& lhs, const UniformData& rhs) const {
    284     return lhs.queried_name < rhs.queried_name;
    285   }
    286 };
    287 
    288 }  // anonymous namespace
    289 
    290 void Program::Update() {
    291   Reset();
    292   UpdateLogInfo();
    293   link_status_ = true;
    294   uniforms_cleared_ = false;
    295   GLint num_attribs = 0;
    296   GLint max_len = 0;
    297   GLint max_location = -1;
    298   glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs);
    299   glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
    300   // TODO(gman): Should we check for error?
    301   scoped_ptr<char[]> name_buffer(new char[max_len]);
    302   for (GLint ii = 0; ii < num_attribs; ++ii) {
    303     GLsizei length = 0;
    304     GLsizei size = 0;
    305     GLenum type = 0;
    306     glGetActiveAttrib(
    307         service_id_, ii, max_len, &length, &size, &type, name_buffer.get());
    308     DCHECK(max_len == 0 || length < max_len);
    309     DCHECK(length == 0 || name_buffer[length] == '\0');
    310     if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
    311       std::string name;
    312       std::string original_name;
    313       GetCorrectedVariableInfo(
    314           false, name_buffer.get(), &name, &original_name, &size, &type);
    315       // TODO(gman): Should we check for error?
    316       GLint location = glGetAttribLocation(service_id_, name_buffer.get());
    317       if (location > max_location) {
    318         max_location = location;
    319       }
    320       attrib_infos_.push_back(
    321           VertexAttrib(size, type, original_name, location));
    322       max_attrib_name_length_ = std::max(
    323           max_attrib_name_length_, static_cast<GLsizei>(original_name.size()));
    324     }
    325   }
    326 
    327   // Create attrib location to index map.
    328   attrib_location_to_index_map_.resize(max_location + 1);
    329   for (GLint ii = 0; ii <= max_location; ++ii) {
    330     attrib_location_to_index_map_[ii] = -1;
    331   }
    332   for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
    333     const VertexAttrib& info = attrib_infos_[ii];
    334     attrib_location_to_index_map_[info.location] = ii;
    335   }
    336 
    337 #if !defined(NDEBUG)
    338   if (CommandLine::ForCurrentProcess()->HasSwitch(
    339       switches::kEnableGPUServiceLoggingGPU)) {
    340     DLOG(INFO) << "----: attribs for service_id: " << service_id();
    341     for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
    342       const VertexAttrib& info = attrib_infos_[ii];
    343       DLOG(INFO) << ii << ": loc = " << info.location
    344                  << ", size = " << info.size
    345                  << ", type = " << GLES2Util::GetStringEnum(info.type)
    346                  << ", name = " << info.name;
    347     }
    348   }
    349 #endif
    350 
    351   max_len = 0;
    352   GLint num_uniforms = 0;
    353   glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
    354   glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
    355   name_buffer.reset(new char[max_len]);
    356 
    357   // Reads all the names.
    358   std::vector<UniformData> uniform_data_;
    359   for (GLint ii = 0; ii < num_uniforms; ++ii) {
    360     GLsizei length = 0;
    361     UniformData data;
    362     glGetActiveUniform(
    363         service_id_, ii, max_len, &length,
    364         &data.size, &data.type, name_buffer.get());
    365     DCHECK(max_len == 0 || length < max_len);
    366     DCHECK(length == 0 || name_buffer[length] == '\0');
    367     if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
    368       data.queried_name = std::string(name_buffer.get());
    369       GetCorrectedVariableInfo(
    370           true, name_buffer.get(), &data.corrected_name, &data.original_name,
    371           &data.size, &data.type);
    372       uniform_data_.push_back(data);
    373     }
    374   }
    375 
    376   // NOTE: We don't care if 2 uniforms are bound to the same location.
    377   // One of them will take preference. The spec allows this, same as
    378   // BindAttribLocation.
    379   //
    380   // The reason we don't check is if we were to fail we'd have to
    381   // restore the previous program but since we've already linked successfully
    382   // at this point the previous program is gone.
    383 
    384   // Assigns the uniforms with bindings.
    385   size_t next_available_index = 0;
    386   for (size_t ii = 0; ii < uniform_data_.size(); ++ii) {
    387     UniformData& data = uniform_data_[ii];
    388     data.location = glGetUniformLocation(
    389         service_id_, data.queried_name.c_str());
    390     // remove "[0]"
    391     std::string short_name;
    392     int element_index = 0;
    393     bool good ALLOW_UNUSED = GetUniformNameSansElement(
    394         data.queried_name, &element_index, &short_name);\
    395     DCHECK(good);
    396     LocationMap::const_iterator it = bind_uniform_location_map_.find(
    397         short_name);
    398     if (it != bind_uniform_location_map_.end()) {
    399       data.added = AddUniformInfo(
    400           data.size, data.type, data.location, it->second, data.corrected_name,
    401           data.original_name, &next_available_index);
    402     }
    403   }
    404 
    405   // Assigns the uniforms that were not bound.
    406   for (size_t ii = 0; ii < uniform_data_.size(); ++ii) {
    407     const UniformData& data = uniform_data_[ii];
    408     if (!data.added) {
    409       AddUniformInfo(
    410           data.size, data.type, data.location, -1, data.corrected_name,
    411           data.original_name, &next_available_index);
    412     }
    413   }
    414 
    415 #if !defined(NDEBUG)
    416   if (CommandLine::ForCurrentProcess()->HasSwitch(
    417       switches::kEnableGPUServiceLoggingGPU)) {
    418     DLOG(INFO) << "----: uniforms for service_id: " << service_id();
    419     for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
    420       const UniformInfo& info = uniform_infos_[ii];
    421       if (info.IsValid()) {
    422         DLOG(INFO) << ii << ": loc = " << info.element_locations[0]
    423                    << ", size = " << info.size
    424                    << ", type = " << GLES2Util::GetStringEnum(info.type)
    425                    << ", name = " << info.name;
    426       }
    427     }
    428   }
    429 #endif
    430 
    431   valid_ = true;
    432 }
    433 
    434 void Program::ExecuteBindAttribLocationCalls() {
    435   for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
    436        it != bind_attrib_location_map_.end(); ++it) {
    437     const std::string* mapped_name = GetAttribMappedName(it->first);
    438     if (mapped_name && *mapped_name != it->first)
    439       glBindAttribLocation(service_id_, it->second, mapped_name->c_str());
    440   }
    441 }
    442 
    443 void ProgramManager::DoCompileShader(Shader* shader,
    444                                      ShaderTranslator* translator,
    445                                      FeatureInfo* feature_info) {
    446   // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
    447   // glShaderSource and then glCompileShader.
    448   const std::string* source = shader->source();
    449   const char* shader_src = source ? source->c_str() : "";
    450   if (translator) {
    451     if (!translator->Translate(shader_src)) {
    452       shader->SetStatus(false, translator->info_log(), NULL);
    453       return;
    454     }
    455     shader_src = translator->translated_shader();
    456     if (!feature_info->feature_flags().angle_translated_shader_source)
    457       shader->UpdateTranslatedSource(shader_src);
    458   }
    459 
    460   glShaderSource(shader->service_id(), 1, &shader_src, NULL);
    461   glCompileShader(shader->service_id());
    462   if (feature_info->feature_flags().angle_translated_shader_source) {
    463     GLint max_len = 0;
    464     glGetShaderiv(shader->service_id(),
    465                   GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
    466                   &max_len);
    467     scoped_ptr<char[]> temp(new char[max_len]);
    468     GLint len = 0;
    469     glGetTranslatedShaderSourceANGLE(
    470         shader->service_id(), max_len, &len, temp.get());
    471     DCHECK(max_len == 0 || len < max_len);
    472     DCHECK(len == 0 || temp[len] == '\0');
    473     shader->UpdateTranslatedSource(max_len ? temp.get() : NULL);
    474   }
    475 
    476   GLint status = GL_FALSE;
    477   glGetShaderiv(shader->service_id(), GL_COMPILE_STATUS, &status);
    478   if (status) {
    479     shader->SetStatus(true, "", translator);
    480   } else {
    481     // We cannot reach here if we are using the shader translator.
    482     // All invalid shaders must be rejected by the translator.
    483     // All translated shaders must compile.
    484     GLint max_len = 0;
    485     glGetShaderiv(shader->service_id(), GL_INFO_LOG_LENGTH, &max_len);
    486     scoped_ptr<char[]> temp(new char[max_len]);
    487     GLint len = 0;
    488     glGetShaderInfoLog(shader->service_id(), max_len, &len, temp.get());
    489     DCHECK(max_len == 0 || len < max_len);
    490     DCHECK(len == 0 || temp[len] == '\0');
    491     shader->SetStatus(false, std::string(temp.get(), len).c_str(), NULL);
    492     LOG_IF(ERROR, translator)
    493         << "Shader translator allowed/produced an invalid shader "
    494         << "unless the driver is buggy:"
    495         << "\n--original-shader--\n" << (source ? *source : std::string())
    496         << "\n--translated-shader--\n" << shader_src << "\n--info-log--\n"
    497         << *shader->log_info();
    498   }
    499 }
    500 
    501 bool Program::Link(ShaderManager* manager,
    502                    ShaderTranslator* vertex_translator,
    503                    ShaderTranslator* fragment_translator,
    504                    FeatureInfo* feature_info,
    505                    const ShaderCacheCallback& shader_callback) {
    506   ClearLinkStatus();
    507   if (!CanLink()) {
    508     set_log_info("missing shaders");
    509     return false;
    510   }
    511   if (DetectAttribLocationBindingConflicts()) {
    512     set_log_info("glBindAttribLocation() conflicts");
    513     return false;
    514   }
    515 
    516   TimeTicks before_time = TimeTicks::HighResNow();
    517   bool link = true;
    518   ProgramCache* cache = manager_->program_cache_;
    519   if (cache) {
    520     DCHECK(attached_shaders_[0]->signature_source() &&
    521            attached_shaders_[1]->signature_source());
    522     ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
    523         *attached_shaders_[0]->signature_source(),
    524         vertex_translator,
    525         *attached_shaders_[1]->signature_source(),
    526         fragment_translator,
    527         &bind_attrib_location_map_);
    528 
    529     if (status == ProgramCache::LINK_SUCCEEDED) {
    530       ProgramCache::ProgramLoadResult success =
    531           cache->LoadLinkedProgram(service_id(),
    532                                    attached_shaders_[0].get(),
    533                                    vertex_translator,
    534                                    attached_shaders_[1].get(),
    535                                    fragment_translator,
    536                                    &bind_attrib_location_map_,
    537                                    shader_callback);
    538       link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
    539       UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
    540     }
    541   }
    542 
    543   if (link) {
    544     ExecuteBindAttribLocationCalls();
    545     before_time = TimeTicks::HighResNow();
    546     if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
    547       glProgramParameteri(service_id(),
    548                           PROGRAM_BINARY_RETRIEVABLE_HINT,
    549                           GL_TRUE);
    550     }
    551     glLinkProgram(service_id());
    552   }
    553 
    554   GLint success = 0;
    555   glGetProgramiv(service_id(), GL_LINK_STATUS, &success);
    556   if (success == GL_TRUE) {
    557     Update();
    558     if (link) {
    559       if (cache) {
    560         cache->SaveLinkedProgram(service_id(),
    561                                  attached_shaders_[0].get(),
    562                                  vertex_translator,
    563                                  attached_shaders_[1].get(),
    564                                  fragment_translator,
    565                                  &bind_attrib_location_map_,
    566                                  shader_callback);
    567       }
    568       UMA_HISTOGRAM_CUSTOM_COUNTS(
    569           "GPU.ProgramCache.BinaryCacheMissTime",
    570           (TimeTicks::HighResNow() - before_time).InMicroseconds(),
    571           0,
    572           TimeDelta::FromSeconds(10).InMicroseconds(),
    573           50);
    574     } else {
    575       UMA_HISTOGRAM_CUSTOM_COUNTS(
    576           "GPU.ProgramCache.BinaryCacheHitTime",
    577           (TimeTicks::HighResNow() - before_time).InMicroseconds(),
    578           0,
    579           TimeDelta::FromSeconds(1).InMicroseconds(),
    580           50);
    581     }
    582   } else {
    583     UpdateLogInfo();
    584   }
    585   return success == GL_TRUE;
    586 }
    587 
    588 void Program::Validate() {
    589   if (!IsValid()) {
    590     set_log_info("program not linked");
    591     return;
    592   }
    593   glValidateProgram(service_id());
    594   UpdateLogInfo();
    595 }
    596 
    597 GLint Program::GetUniformFakeLocation(
    598     const std::string& name) const {
    599   bool getting_array_location = false;
    600   size_t open_pos = std::string::npos;
    601   int index = 0;
    602   if (!GLES2Util::ParseUniformName(
    603       name, &open_pos, &index, &getting_array_location)) {
    604     return -1;
    605   }
    606   for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
    607     const UniformInfo& info = uniform_infos_[ii];
    608     if (!info.IsValid()) {
    609       continue;
    610     }
    611     if (info.name == name ||
    612         (info.is_array &&
    613          info.name.compare(0, info.name.size() - 3, name) == 0)) {
    614       return info.fake_location_base;
    615     } else if (getting_array_location && info.is_array) {
    616       // Look for an array specification.
    617       size_t open_pos_2 = info.name.find_last_of('[');
    618       if (open_pos_2 == open_pos &&
    619           name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
    620         if (index >= 0 && index < info.size) {
    621           return ProgramManager::MakeFakeLocation(
    622               info.fake_location_base, index);
    623         }
    624       }
    625     }
    626   }
    627   return -1;
    628 }
    629 
    630 GLint Program::GetAttribLocation(
    631     const std::string& name) const {
    632   for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
    633     const VertexAttrib& info = attrib_infos_[ii];
    634     if (info.name == name) {
    635       return info.location;
    636     }
    637   }
    638   return -1;
    639 }
    640 
    641 const Program::UniformInfo*
    642     Program::GetUniformInfoByFakeLocation(
    643         GLint fake_location, GLint* real_location, GLint* array_index) const {
    644   DCHECK(real_location);
    645   DCHECK(array_index);
    646   if (fake_location < 0) {
    647     return NULL;
    648   }
    649 
    650   GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
    651   if (uniform_index >= 0 &&
    652       static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
    653     const UniformInfo& uniform_info = uniform_infos_[uniform_index];
    654     if (!uniform_info.IsValid()) {
    655       return NULL;
    656     }
    657     GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
    658     if (element_index < uniform_info.size) {
    659       *real_location = uniform_info.element_locations[element_index];
    660       *array_index = element_index;
    661       return &uniform_info;
    662     }
    663   }
    664   return NULL;
    665 }
    666 
    667 const std::string* Program::GetAttribMappedName(
    668     const std::string& original_name) const {
    669   for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
    670     Shader* shader = attached_shaders_[ii].get();
    671     if (shader) {
    672       const std::string* mapped_name =
    673           shader->GetAttribMappedName(original_name);
    674       if (mapped_name)
    675         return mapped_name;
    676     }
    677   }
    678   return NULL;
    679 }
    680 
    681 const std::string* Program::GetOriginalNameFromHashedName(
    682     const std::string& hashed_name) const {
    683   for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
    684     Shader* shader = attached_shaders_[ii].get();
    685     if (shader) {
    686       const std::string* original_name =
    687           shader->GetOriginalNameFromHashedName(hashed_name);
    688       if (original_name)
    689         return original_name;
    690     }
    691   }
    692   return NULL;
    693 }
    694 
    695 bool Program::SetUniformLocationBinding(
    696     const std::string& name, GLint location) {
    697   std::string short_name;
    698   int element_index = 0;
    699   if (!GetUniformNameSansElement(name, &element_index, &short_name) ||
    700       element_index != 0) {
    701     return false;
    702   }
    703 
    704   bind_uniform_location_map_[short_name] = location;
    705   return true;
    706 }
    707 
    708 // Note: This is only valid to call right after a program has been linked
    709 // successfully.
    710 void Program::GetCorrectedVariableInfo(
    711     bool use_uniforms,
    712     const std::string& name, std::string* corrected_name,
    713     std::string* original_name,
    714     GLsizei* size, GLenum* type) const {
    715   DCHECK(corrected_name);
    716   DCHECK(original_name);
    717   DCHECK(size);
    718   DCHECK(type);
    719   const char* kArraySpec = "[0]";
    720   for (int jj = 0; jj < 2; ++jj) {
    721     std::string test_name(name + ((jj == 1) ? kArraySpec : ""));
    722     for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
    723       Shader* shader = attached_shaders_[ii].get();
    724       if (shader) {
    725         const Shader::VariableInfo* variable_info =
    726             use_uniforms ? shader->GetUniformInfo(test_name) :
    727                            shader->GetAttribInfo(test_name);
    728         // Note: There is an assuption here that if an attrib is defined in more
    729         // than 1 attached shader their types and sizes match. Should we check
    730         // for that case?
    731         if (variable_info) {
    732           *corrected_name = test_name;
    733           *original_name = variable_info->name;
    734           *type = variable_info->type;
    735           *size = variable_info->size;
    736           return;
    737         }
    738       }
    739     }
    740   }
    741   *corrected_name = name;
    742   *original_name = name;
    743 }
    744 
    745 bool Program::AddUniformInfo(
    746         GLsizei size, GLenum type, GLint location, GLint fake_base_location,
    747         const std::string& name, const std::string& original_name,
    748         size_t* next_available_index) {
    749   DCHECK(next_available_index);
    750   const char* kArraySpec = "[0]";
    751   size_t uniform_index =
    752       fake_base_location >= 0 ? fake_base_location : *next_available_index;
    753   if (uniform_infos_.size() < uniform_index + 1) {
    754     uniform_infos_.resize(uniform_index + 1);
    755   }
    756 
    757   // return if this location is already in use.
    758   if (uniform_infos_[uniform_index].IsValid()) {
    759     DCHECK_GE(fake_base_location, 0);
    760     return false;
    761   }
    762 
    763   uniform_infos_[uniform_index] = UniformInfo(
    764       size, type, uniform_index, original_name);
    765   ++num_uniforms_;
    766 
    767   UniformInfo& info = uniform_infos_[uniform_index];
    768   info.element_locations.resize(size);
    769   info.element_locations[0] = location;
    770   DCHECK_GE(size, 0);
    771   size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
    772   info.texture_units.clear();
    773   info.texture_units.resize(num_texture_units, 0);
    774 
    775   if (size > 1) {
    776     // Go through the array element locations looking for a match.
    777     // We can skip the first element because it's the same as the
    778     // the location without the array operators.
    779     size_t array_pos = name.rfind(kArraySpec);
    780     std::string base_name = name;
    781     if (name.size() > 3) {
    782       if (array_pos != name.size() - 3) {
    783         info.name = name + kArraySpec;
    784       } else {
    785         base_name = name.substr(0, name.size() - 3);
    786       }
    787     }
    788     for (GLsizei ii = 1; ii < info.size; ++ii) {
    789       std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
    790       info.element_locations[ii] =
    791           glGetUniformLocation(service_id_, element_name.c_str());
    792     }
    793   }
    794 
    795   info.is_array =
    796      (size > 1 ||
    797       (info.name.size() > 3 &&
    798        info.name.rfind(kArraySpec) == info.name.size() - 3));
    799 
    800   if (info.IsSampler()) {
    801     sampler_indices_.push_back(info.fake_location_base);
    802   }
    803   max_uniform_name_length_ =
    804       std::max(max_uniform_name_length_,
    805                static_cast<GLsizei>(info.name.size()));
    806 
    807   while (*next_available_index < uniform_infos_.size() &&
    808          uniform_infos_[*next_available_index].IsValid()) {
    809     *next_available_index = *next_available_index + 1;
    810   }
    811 
    812   return true;
    813 }
    814 
    815 const Program::UniformInfo*
    816     Program::GetUniformInfo(
    817         GLint index) const {
    818   if (static_cast<size_t>(index) >= uniform_infos_.size()) {
    819     return NULL;
    820   }
    821 
    822   const UniformInfo& info = uniform_infos_[index];
    823   return info.IsValid() ? &info : NULL;
    824 }
    825 
    826 bool Program::SetSamplers(
    827     GLint num_texture_units, GLint fake_location,
    828     GLsizei count, const GLint* value) {
    829   if (fake_location < 0) {
    830     return true;
    831   }
    832   GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
    833   if (uniform_index >= 0 &&
    834       static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
    835     UniformInfo& info = uniform_infos_[uniform_index];
    836     if (!info.IsValid()) {
    837       return false;
    838     }
    839     GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
    840     if (element_index < info.size) {
    841       count = std::min(info.size - element_index, count);
    842       if (info.IsSampler() && count > 0) {
    843         for (GLsizei ii = 0; ii < count; ++ii) {
    844           if (value[ii] < 0 || value[ii] >= num_texture_units) {
    845             return false;
    846           }
    847         }
    848         std::copy(value, value + count,
    849                   info.texture_units.begin() + element_index);
    850         return true;
    851       }
    852     }
    853   }
    854   return true;
    855 }
    856 
    857 void Program::GetProgramiv(GLenum pname, GLint* params) {
    858   switch (pname) {
    859     case GL_ACTIVE_ATTRIBUTES:
    860       *params = attrib_infos_.size();
    861       break;
    862     case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
    863       // Notice +1 to accomodate NULL terminator.
    864       *params = max_attrib_name_length_ + 1;
    865       break;
    866     case GL_ACTIVE_UNIFORMS:
    867       *params = num_uniforms_;
    868       break;
    869     case GL_ACTIVE_UNIFORM_MAX_LENGTH:
    870       // Notice +1 to accomodate NULL terminator.
    871       *params = max_uniform_name_length_ + 1;
    872       break;
    873     case GL_LINK_STATUS:
    874       *params = link_status_;
    875       break;
    876     case GL_INFO_LOG_LENGTH:
    877       // Notice +1 to accomodate NULL terminator.
    878       *params = log_info_.get() ? (log_info_->size() + 1) : 0;
    879       break;
    880     case GL_DELETE_STATUS:
    881       *params = deleted_;
    882       break;
    883     case GL_VALIDATE_STATUS:
    884       if (!IsValid()) {
    885         *params = GL_FALSE;
    886       } else {
    887         glGetProgramiv(service_id_, pname, params);
    888       }
    889       break;
    890     default:
    891       glGetProgramiv(service_id_, pname, params);
    892       break;
    893   }
    894 }
    895 
    896 bool Program::AttachShader(
    897     ShaderManager* shader_manager,
    898     Shader* shader) {
    899   DCHECK(shader_manager);
    900   DCHECK(shader);
    901   int index = ShaderTypeToIndex(shader->shader_type());
    902   if (attached_shaders_[index].get() != NULL) {
    903     return false;
    904   }
    905   attached_shaders_[index] = scoped_refptr<Shader>(shader);
    906   shader_manager->UseShader(shader);
    907   return true;
    908 }
    909 
    910 bool Program::DetachShader(
    911     ShaderManager* shader_manager,
    912     Shader* shader) {
    913   DCHECK(shader_manager);
    914   DCHECK(shader);
    915   if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() !=
    916       shader) {
    917     return false;
    918   }
    919   attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL;
    920   shader_manager->UnuseShader(shader);
    921   return true;
    922 }
    923 
    924 void Program::DetachShaders(ShaderManager* shader_manager) {
    925   DCHECK(shader_manager);
    926   for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
    927     if (attached_shaders_[ii].get()) {
    928       DetachShader(shader_manager, attached_shaders_[ii].get());
    929     }
    930   }
    931 }
    932 
    933 bool Program::CanLink() const {
    934   for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
    935     if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid()) {
    936       return false;
    937     }
    938   }
    939   return true;
    940 }
    941 
    942 bool Program::DetectAttribLocationBindingConflicts() const {
    943   std::set<GLint> location_binding_used;
    944   for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
    945        it != bind_attrib_location_map_.end(); ++it) {
    946     // Find out if an attribute is declared in this program's shaders.
    947     bool active = false;
    948     for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
    949       if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid())
    950         continue;
    951       if (attached_shaders_[ii]->GetAttribInfo(it->first)) {
    952         active = true;
    953         break;
    954       }
    955     }
    956     if (active) {
    957       std::pair<std::set<GLint>::iterator, bool> result =
    958           location_binding_used.insert(it->second);
    959       if (!result.second)
    960         return true;
    961     }
    962   }
    963   return false;
    964 }
    965 
    966 static uint32 ComputeOffset(const void* start, const void* position) {
    967   return static_cast<const uint8*>(position) -
    968          static_cast<const uint8*>(start);
    969 }
    970 
    971 void Program::GetProgramInfo(
    972     ProgramManager* manager, CommonDecoder::Bucket* bucket) const {
    973   // NOTE: It seems to me the math in here does not need check for overflow
    974   // because the data being calucated from has various small limits. The max
    975   // number of attribs + uniforms is somewhere well under 1024. The maximum size
    976   // of an identifier is 256 characters.
    977   uint32 num_locations = 0;
    978   uint32 total_string_size = 0;
    979 
    980   for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
    981     const VertexAttrib& info = attrib_infos_[ii];
    982     num_locations += 1;
    983     total_string_size += info.name.size();
    984   }
    985 
    986   for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
    987     const UniformInfo& info = uniform_infos_[ii];
    988     if (info.IsValid()) {
    989       num_locations += info.element_locations.size();
    990       total_string_size += info.name.size();
    991     }
    992   }
    993 
    994   uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
    995   uint32 input_size = num_inputs * sizeof(ProgramInput);
    996   uint32 location_size = num_locations * sizeof(int32);
    997   uint32 size = sizeof(ProgramInfoHeader) +
    998       input_size + location_size + total_string_size;
    999 
   1000   bucket->SetSize(size);
   1001   ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
   1002   ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
   1003       sizeof(ProgramInfoHeader), input_size);
   1004   int32* locations = bucket->GetDataAs<int32*>(
   1005       sizeof(ProgramInfoHeader) + input_size, location_size);
   1006   char* strings = bucket->GetDataAs<char*>(
   1007       sizeof(ProgramInfoHeader) + input_size + location_size,
   1008       total_string_size);
   1009   DCHECK(header);
   1010   DCHECK(inputs);
   1011   DCHECK(locations);
   1012   DCHECK(strings);
   1013 
   1014   header->link_status = link_status_;
   1015   header->num_attribs = attrib_infos_.size();
   1016   header->num_uniforms = num_uniforms_;
   1017 
   1018   for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
   1019     const VertexAttrib& info = attrib_infos_[ii];
   1020     inputs->size = info.size;
   1021     inputs->type = info.type;
   1022     inputs->location_offset = ComputeOffset(header, locations);
   1023     inputs->name_offset = ComputeOffset(header, strings);
   1024     inputs->name_length = info.name.size();
   1025     *locations++ = info.location;
   1026     memcpy(strings, info.name.c_str(), info.name.size());
   1027     strings += info.name.size();
   1028     ++inputs;
   1029   }
   1030 
   1031   for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
   1032     const UniformInfo& info = uniform_infos_[ii];
   1033     if (info.IsValid()) {
   1034       inputs->size = info.size;
   1035       inputs->type = info.type;
   1036       inputs->location_offset = ComputeOffset(header, locations);
   1037       inputs->name_offset = ComputeOffset(header, strings);
   1038       inputs->name_length = info.name.size();
   1039       DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
   1040       for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
   1041         *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
   1042       }
   1043       memcpy(strings, info.name.c_str(), info.name.size());
   1044       strings += info.name.size();
   1045       ++inputs;
   1046     }
   1047   }
   1048 
   1049   DCHECK_EQ(ComputeOffset(header, strings), size);
   1050 }
   1051 
   1052 Program::~Program() {
   1053   if (manager_) {
   1054     if (manager_->have_context_) {
   1055       glDeleteProgram(service_id());
   1056     }
   1057     manager_->StopTracking(this);
   1058     manager_ = NULL;
   1059   }
   1060 }
   1061 
   1062 
   1063 ProgramManager::ProgramManager(ProgramCache* program_cache)
   1064     : program_count_(0),
   1065       have_context_(true),
   1066       disable_workarounds_(
   1067           CommandLine::ForCurrentProcess()->HasSwitch(
   1068               switches::kDisableGpuDriverBugWorkarounds)),
   1069       program_cache_(program_cache) { }
   1070 
   1071 ProgramManager::~ProgramManager() {
   1072   DCHECK(programs_.empty());
   1073 }
   1074 
   1075 void ProgramManager::Destroy(bool have_context) {
   1076   have_context_ = have_context;
   1077   programs_.clear();
   1078 }
   1079 
   1080 void ProgramManager::StartTracking(Program* /* program */) {
   1081   ++program_count_;
   1082 }
   1083 
   1084 void ProgramManager::StopTracking(Program* /* program */) {
   1085   --program_count_;
   1086 }
   1087 
   1088 Program* ProgramManager::CreateProgram(
   1089     GLuint client_id, GLuint service_id) {
   1090   std::pair<ProgramMap::iterator, bool> result =
   1091       programs_.insert(
   1092           std::make_pair(client_id,
   1093                          scoped_refptr<Program>(
   1094                              new Program(this, service_id))));
   1095   DCHECK(result.second);
   1096   return result.first->second.get();
   1097 }
   1098 
   1099 Program* ProgramManager::GetProgram(GLuint client_id) {
   1100   ProgramMap::iterator it = programs_.find(client_id);
   1101   return it != programs_.end() ? it->second.get() : NULL;
   1102 }
   1103 
   1104 bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
   1105   // This doesn't need to be fast. It's only used during slow queries.
   1106   for (ProgramMap::const_iterator it = programs_.begin();
   1107        it != programs_.end(); ++it) {
   1108     if (it->second->service_id() == service_id) {
   1109       *client_id = it->first;
   1110       return true;
   1111     }
   1112   }
   1113   return false;
   1114 }
   1115 
   1116 ProgramCache* ProgramManager::program_cache() const {
   1117   return program_cache_;
   1118 }
   1119 
   1120 bool ProgramManager::IsOwned(Program* program) {
   1121   for (ProgramMap::iterator it = programs_.begin();
   1122        it != programs_.end(); ++it) {
   1123     if (it->second.get() == program) {
   1124       return true;
   1125     }
   1126   }
   1127   return false;
   1128 }
   1129 
   1130 void ProgramManager::RemoveProgramInfoIfUnused(
   1131     ShaderManager* shader_manager, Program* program) {
   1132   DCHECK(shader_manager);
   1133   DCHECK(program);
   1134   DCHECK(IsOwned(program));
   1135   if (program->IsDeleted() && !program->InUse()) {
   1136     program->DetachShaders(shader_manager);
   1137     for (ProgramMap::iterator it = programs_.begin();
   1138          it != programs_.end(); ++it) {
   1139       if (it->second.get() == program) {
   1140         programs_.erase(it);
   1141         return;
   1142       }
   1143     }
   1144     NOTREACHED();
   1145   }
   1146 }
   1147 
   1148 void ProgramManager::MarkAsDeleted(
   1149     ShaderManager* shader_manager,
   1150     Program* program) {
   1151   DCHECK(shader_manager);
   1152   DCHECK(program);
   1153   DCHECK(IsOwned(program));
   1154   program->MarkAsDeleted();
   1155   RemoveProgramInfoIfUnused(shader_manager, program);
   1156 }
   1157 
   1158 void ProgramManager::UseProgram(Program* program) {
   1159   DCHECK(program);
   1160   DCHECK(IsOwned(program));
   1161   program->IncUseCount();
   1162   ClearUniforms(program);
   1163 }
   1164 
   1165 void ProgramManager::UnuseProgram(
   1166     ShaderManager* shader_manager,
   1167     Program* program) {
   1168   DCHECK(shader_manager);
   1169   DCHECK(program);
   1170   DCHECK(IsOwned(program));
   1171   program->DecUseCount();
   1172   RemoveProgramInfoIfUnused(shader_manager, program);
   1173 }
   1174 
   1175 void ProgramManager::ClearUniforms(Program* program) {
   1176   DCHECK(program);
   1177   if (!disable_workarounds_) {
   1178     program->ClearUniforms(&zero_);
   1179   }
   1180 }
   1181 
   1182 int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
   1183   return index + element * 0x10000;
   1184 }
   1185 
   1186 }  // namespace gles2
   1187 }  // namespace gpu
   1188