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