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