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
29using base::TimeDelta;
30using base::TimeTicks;
31
32namespace gpu {
33namespace gles2 {
34
35namespace {
36
37int 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
49ShaderTranslator* 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]"
67bool 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
101Program::UniformInfo::UniformInfo()
102    : size(0),
103      type(GL_NONE),
104      fake_location_base(0),
105      is_array(false) {
106}
107
108Program::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
120Program::UniformInfo::~UniformInfo() {}
121
122bool 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
128Program::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
143void 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
155std::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
178void 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
194void 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
268namespace {
269
270struct 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
282struct 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
290void 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
434void 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
443void 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
501bool 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
588void Program::Validate() {
589  if (!IsValid()) {
590    set_log_info("program not linked");
591    return;
592  }
593  glValidateProgram(service_id());
594  UpdateLogInfo();
595}
596
597GLint 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
630GLint 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
641const 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
667const 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
681const 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
695bool 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.
710void 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
745bool 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
815const 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
826bool 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
857void 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
896bool 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
910bool 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
924void 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
933bool 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
942bool 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
966static uint32 ComputeOffset(const void* start, const void* position) {
967  return static_cast<const uint8*>(position) -
968         static_cast<const uint8*>(start);
969}
970
971void 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
1052Program::~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
1063ProgramManager::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
1071ProgramManager::~ProgramManager() {
1072  DCHECK(programs_.empty());
1073}
1074
1075void ProgramManager::Destroy(bool have_context) {
1076  have_context_ = have_context;
1077  programs_.clear();
1078}
1079
1080void ProgramManager::StartTracking(Program* /* program */) {
1081  ++program_count_;
1082}
1083
1084void ProgramManager::StopTracking(Program* /* program */) {
1085  --program_count_;
1086}
1087
1088Program* 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
1099Program* ProgramManager::GetProgram(GLuint client_id) {
1100  ProgramMap::iterator it = programs_.find(client_id);
1101  return it != programs_.end() ? it->second.get() : NULL;
1102}
1103
1104bool 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
1116ProgramCache* ProgramManager::program_cache() const {
1117  return program_cache_;
1118}
1119
1120bool 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
1130void 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
1148void 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
1158void ProgramManager::UseProgram(Program* program) {
1159  DCHECK(program);
1160  DCHECK(IsOwned(program));
1161  program->IncUseCount();
1162  ClearUniforms(program);
1163}
1164
1165void 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
1175void ProgramManager::ClearUniforms(Program* program) {
1176  DCHECK(program);
1177  if (!disable_workarounds_) {
1178    program->ClearUniforms(&zero_);
1179  }
1180}
1181
1182int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
1183  return index + element * 0x10000;
1184}
1185
1186}  // namespace gles2
1187}  // namespace gpu
1188