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