Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / gpu / command_buffer / service / program_manager.cc
blob4fe76dba1057c6bdc63010a1f59a15e2da2dfcf5
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.
5 #include "gpu/command_buffer/service/program_manager.h"
7 #include <algorithm>
8 #include <set>
9 #include <utility>
10 #include <vector>
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/numerics/safe_math.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h"
20 #include "base/time/time.h"
21 #include "gpu/command_buffer/common/gles2_cmd_format.h"
22 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
23 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
24 #include "gpu/command_buffer/service/gpu_switches.h"
25 #include "gpu/command_buffer/service/program_cache.h"
26 #include "gpu/command_buffer/service/shader_manager.h"
27 #include "third_party/re2/re2/re2.h"
29 using base::TimeDelta;
30 using base::TimeTicks;
32 namespace gpu {
33 namespace gles2 {
35 namespace {
37 int ShaderTypeToIndex(GLenum shader_type) {
38 switch (shader_type) {
39 case GL_VERTEX_SHADER:
40 return 0;
41 case GL_FRAGMENT_SHADER:
42 return 1;
43 default:
44 NOTREACHED();
45 return 0;
49 // Given a name like "foo.bar[123].moo[456]" sets new_name to "foo.bar[123].moo"
50 // and sets element_index to 456. returns false if element expression was not a
51 // whole decimal number. For example: "foo[1b2]"
52 bool GetUniformNameSansElement(
53 const std::string& name, int* element_index, std::string* new_name) {
54 DCHECK(element_index);
55 DCHECK(new_name);
56 if (name.size() < 3 || name[name.size() - 1] != ']') {
57 *element_index = 0;
58 *new_name = name;
59 return true;
62 // Look for an array specification.
63 size_t open_pos = name.find_last_of('[');
64 if (open_pos == std::string::npos ||
65 open_pos >= name.size() - 2) {
66 return false;
69 base::CheckedNumeric<GLint> index = 0;
70 size_t last = name.size() - 1;
71 for (size_t pos = open_pos + 1; pos < last; ++pos) {
72 int8 digit = name[pos] - '0';
73 if (digit < 0 || digit > 9) {
74 return false;
76 index = index * 10 + digit;
78 if (!index.IsValid()) {
79 return false;
82 *element_index = index.ValueOrDie();
83 *new_name = name.substr(0, open_pos);
84 return true;
87 bool IsBuiltInFragmentVarying(const std::string& name) {
88 // Built-in variables for fragment shaders.
89 const char* kBuiltInVaryings[] = {
90 "gl_FragCoord",
91 "gl_FrontFacing",
92 "gl_PointCoord"
94 for (size_t ii = 0; ii < arraysize(kBuiltInVaryings); ++ii) {
95 if (name == kBuiltInVaryings[ii])
96 return true;
98 return false;
101 bool IsBuiltInInvariant(
102 const VaryingMap& varyings, const std::string& name) {
103 VaryingMap::const_iterator hit = varyings.find(name);
104 if (hit == varyings.end())
105 return false;
106 return hit->second.isInvariant;
109 uint32 ComputeOffset(const void* start, const void* position) {
110 return static_cast<const uint8*>(position) -
111 static_cast<const uint8*>(start);
114 } // anonymous namespace.
116 Program::UniformInfo::UniformInfo()
117 : size(0),
118 type(GL_NONE),
119 fake_location_base(0),
120 is_array(false) {
123 Program::UniformInfo::UniformInfo(GLsizei _size,
124 GLenum _type,
125 int _fake_location_base,
126 const std::string& _name)
127 : size(_size),
128 type(_type),
129 accepts_api_type(0),
130 fake_location_base(_fake_location_base),
131 is_array(false),
132 name(_name) {
133 switch (type) {
134 case GL_INT:
135 accepts_api_type = kUniform1i;
136 break;
137 case GL_INT_VEC2:
138 accepts_api_type = kUniform2i;
139 break;
140 case GL_INT_VEC3:
141 accepts_api_type = kUniform3i;
142 break;
143 case GL_INT_VEC4:
144 accepts_api_type = kUniform4i;
145 break;
147 case GL_BOOL:
148 accepts_api_type = kUniform1i | kUniform1f;
149 break;
150 case GL_BOOL_VEC2:
151 accepts_api_type = kUniform2i | kUniform2f;
152 break;
153 case GL_BOOL_VEC3:
154 accepts_api_type = kUniform3i | kUniform3f;
155 break;
156 case GL_BOOL_VEC4:
157 accepts_api_type = kUniform4i | kUniform4f;
158 break;
160 case GL_FLOAT:
161 accepts_api_type = kUniform1f;
162 break;
163 case GL_FLOAT_VEC2:
164 accepts_api_type = kUniform2f;
165 break;
166 case GL_FLOAT_VEC3:
167 accepts_api_type = kUniform3f;
168 break;
169 case GL_FLOAT_VEC4:
170 accepts_api_type = kUniform4f;
171 break;
173 case GL_FLOAT_MAT2:
174 accepts_api_type = kUniformMatrix2f;
175 break;
176 case GL_FLOAT_MAT3:
177 accepts_api_type = kUniformMatrix3f;
178 break;
179 case GL_FLOAT_MAT4:
180 accepts_api_type = kUniformMatrix4f;
181 break;
183 case GL_SAMPLER_2D:
184 case GL_SAMPLER_2D_RECT_ARB:
185 case GL_SAMPLER_CUBE:
186 case GL_SAMPLER_3D_OES:
187 case GL_SAMPLER_EXTERNAL_OES:
188 accepts_api_type = kUniform1i;
189 break;
190 default:
191 NOTREACHED() << "Unhandled UniformInfo type " << type;
192 break;
196 Program::UniformInfo::~UniformInfo() {}
198 bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
199 static const char kInvalidPrefix[] = { 'g', 'l', '_' };
200 return (length >= sizeof(kInvalidPrefix) &&
201 memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
204 Program::Program(ProgramManager* manager, GLuint service_id)
205 : manager_(manager),
206 use_count_(0),
207 max_attrib_name_length_(0),
208 max_uniform_name_length_(0),
209 service_id_(service_id),
210 deleted_(false),
211 valid_(false),
212 link_status_(false),
213 uniforms_cleared_(false),
214 num_uniforms_(0),
215 transform_feedback_buffer_mode_(GL_NONE) {
216 manager_->StartTracking(this);
219 void Program::Reset() {
220 valid_ = false;
221 link_status_ = false;
222 num_uniforms_ = 0;
223 max_uniform_name_length_ = 0;
224 max_attrib_name_length_ = 0;
225 attrib_infos_.clear();
226 uniform_infos_.clear();
227 sampler_indices_.clear();
228 attrib_location_to_index_map_.clear();
231 std::string Program::ProcessLogInfo(
232 const std::string& log) {
233 std::string output;
234 re2::StringPiece input(log);
235 std::string prior_log;
236 std::string hashed_name;
237 while (RE2::Consume(&input,
238 "(.*?)(webgl_[0123456789abcdefABCDEF]+)",
239 &prior_log,
240 &hashed_name)) {
241 output += prior_log;
243 const std::string* original_name =
244 GetOriginalNameFromHashedName(hashed_name);
245 if (original_name)
246 output += *original_name;
247 else
248 output += hashed_name;
251 return output + input.as_string();
254 void Program::UpdateLogInfo() {
255 GLint max_len = 0;
256 glGetProgramiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
257 if (max_len == 0) {
258 set_log_info(NULL);
259 return;
261 scoped_ptr<char[]> temp(new char[max_len]);
262 GLint len = 0;
263 glGetProgramInfoLog(service_id_, max_len, &len, temp.get());
264 DCHECK(max_len == 0 || len < max_len);
265 DCHECK(len == 0 || temp[len] == '\0');
266 std::string log(temp.get(), len);
267 set_log_info(ProcessLogInfo(log).c_str());
270 void Program::ClearUniforms(
271 std::vector<uint8>* zero_buffer) {
272 DCHECK(zero_buffer);
273 if (uniforms_cleared_) {
274 return;
276 uniforms_cleared_ = true;
277 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
278 const UniformInfo& uniform_info = uniform_infos_[ii];
279 if (!uniform_info.IsValid()) {
280 continue;
282 GLint location = uniform_info.element_locations[0];
283 GLsizei size = uniform_info.size;
284 uint32 unit_size =
285 GLES2Util::GetElementCountForUniformType(uniform_info.type) *
286 GLES2Util::GetElementSizeForUniformType(uniform_info.type);
287 DCHECK_LT(0u, unit_size);
288 uint32 size_needed = size * unit_size;
289 if (size_needed > zero_buffer->size()) {
290 zero_buffer->resize(size_needed, 0u);
292 const void* zero = &(*zero_buffer)[0];
293 switch (uniform_info.type) {
294 case GL_FLOAT:
295 glUniform1fv(location, size, reinterpret_cast<const GLfloat*>(zero));
296 break;
297 case GL_FLOAT_VEC2:
298 glUniform2fv(location, size, reinterpret_cast<const GLfloat*>(zero));
299 break;
300 case GL_FLOAT_VEC3:
301 glUniform3fv(location, size, reinterpret_cast<const GLfloat*>(zero));
302 break;
303 case GL_FLOAT_VEC4:
304 glUniform4fv(location, size, reinterpret_cast<const GLfloat*>(zero));
305 break;
306 case GL_INT:
307 case GL_BOOL:
308 case GL_SAMPLER_2D:
309 case GL_SAMPLER_CUBE:
310 case GL_SAMPLER_EXTERNAL_OES: // extension.
311 case GL_SAMPLER_2D_RECT_ARB: // extension.
312 glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero));
313 break;
314 case GL_INT_VEC2:
315 case GL_BOOL_VEC2:
316 glUniform2iv(location, size, reinterpret_cast<const GLint*>(zero));
317 break;
318 case GL_INT_VEC3:
319 case GL_BOOL_VEC3:
320 glUniform3iv(location, size, reinterpret_cast<const GLint*>(zero));
321 break;
322 case GL_INT_VEC4:
323 case GL_BOOL_VEC4:
324 glUniform4iv(location, size, reinterpret_cast<const GLint*>(zero));
325 break;
326 case GL_FLOAT_MAT2:
327 glUniformMatrix2fv(
328 location, size, false, reinterpret_cast<const GLfloat*>(zero));
329 break;
330 case GL_FLOAT_MAT3:
331 glUniformMatrix3fv(
332 location, size, false, reinterpret_cast<const GLfloat*>(zero));
333 break;
334 case GL_FLOAT_MAT4:
335 glUniformMatrix4fv(
336 location, size, false, reinterpret_cast<const GLfloat*>(zero));
337 break;
339 // ES3 types.
340 case GL_UNSIGNED_INT:
341 glUniform1uiv(location, size, reinterpret_cast<const GLuint*>(zero));
342 break;
343 case GL_SAMPLER_3D:
344 case GL_SAMPLER_2D_SHADOW:
345 case GL_SAMPLER_2D_ARRAY:
346 case GL_SAMPLER_2D_ARRAY_SHADOW:
347 case GL_SAMPLER_CUBE_SHADOW:
348 case GL_INT_SAMPLER_2D:
349 case GL_INT_SAMPLER_3D:
350 case GL_INT_SAMPLER_CUBE:
351 case GL_INT_SAMPLER_2D_ARRAY:
352 case GL_UNSIGNED_INT_SAMPLER_2D:
353 case GL_UNSIGNED_INT_SAMPLER_3D:
354 case GL_UNSIGNED_INT_SAMPLER_CUBE:
355 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
356 glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero));
357 break;
358 case GL_UNSIGNED_INT_VEC2:
359 glUniform2uiv(location, size, reinterpret_cast<const GLuint*>(zero));
360 break;
361 case GL_UNSIGNED_INT_VEC3:
362 glUniform3uiv(location, size, reinterpret_cast<const GLuint*>(zero));
363 break;
364 case GL_UNSIGNED_INT_VEC4:
365 glUniform4uiv(location, size, reinterpret_cast<const GLuint*>(zero));
366 break;
367 case GL_FLOAT_MAT2x3:
368 glUniformMatrix2x3fv(
369 location, size, false, reinterpret_cast<const GLfloat*>(zero));
370 break;
371 case GL_FLOAT_MAT3x2:
372 glUniformMatrix3x2fv(
373 location, size, false, reinterpret_cast<const GLfloat*>(zero));
374 break;
375 case GL_FLOAT_MAT2x4:
376 glUniformMatrix2x4fv(
377 location, size, false, reinterpret_cast<const GLfloat*>(zero));
378 break;
379 case GL_FLOAT_MAT4x2:
380 glUniformMatrix4x2fv(
381 location, size, false, reinterpret_cast<const GLfloat*>(zero));
382 break;
383 case GL_FLOAT_MAT3x4:
384 glUniformMatrix3x4fv(
385 location, size, false, reinterpret_cast<const GLfloat*>(zero));
386 break;
387 case GL_FLOAT_MAT4x3:
388 glUniformMatrix4x3fv(
389 location, size, false, reinterpret_cast<const GLfloat*>(zero));
390 break;
392 default:
393 NOTREACHED();
394 break;
399 namespace {
401 struct UniformData {
402 UniformData() : size(-1), type(GL_NONE), location(0), added(false) {
404 std::string queried_name;
405 std::string corrected_name;
406 std::string original_name;
407 GLsizei size;
408 GLenum type;
409 GLint location;
410 bool added;
413 struct UniformDataComparer {
414 bool operator()(const UniformData& lhs, const UniformData& rhs) const {
415 return lhs.queried_name < rhs.queried_name;
419 } // anonymous namespace
421 void Program::Update() {
422 Reset();
423 UpdateLogInfo();
424 link_status_ = true;
425 uniforms_cleared_ = false;
426 GLint num_attribs = 0;
427 GLint max_len = 0;
428 GLint max_location = -1;
429 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs);
430 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
431 // TODO(gman): Should we check for error?
432 scoped_ptr<char[]> name_buffer(new char[max_len]);
433 for (GLint ii = 0; ii < num_attribs; ++ii) {
434 GLsizei length = 0;
435 GLsizei size = 0;
436 GLenum type = 0;
437 glGetActiveAttrib(
438 service_id_, ii, max_len, &length, &size, &type, name_buffer.get());
439 DCHECK(max_len == 0 || length < max_len);
440 DCHECK(length == 0 || name_buffer[length] == '\0');
441 std::string original_name;
442 GetVertexAttribData(name_buffer.get(), &original_name, &type);
443 // TODO(gman): Should we check for error?
444 GLint location = glGetAttribLocation(service_id_, name_buffer.get());
445 if (location > max_location) {
446 max_location = location;
448 attrib_infos_.push_back(VertexAttrib(1, type, original_name, location));
449 max_attrib_name_length_ = std::max(
450 max_attrib_name_length_, static_cast<GLsizei>(original_name.size()));
453 // Create attrib location to index map.
454 attrib_location_to_index_map_.resize(max_location + 1);
455 for (GLint ii = 0; ii <= max_location; ++ii) {
456 attrib_location_to_index_map_[ii] = -1;
458 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
459 const VertexAttrib& info = attrib_infos_[ii];
460 attrib_location_to_index_map_[info.location] = ii;
463 #if !defined(NDEBUG)
464 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
465 switches::kEnableGPUServiceLoggingGPU)) {
466 DVLOG(1) << "----: attribs for service_id: " << service_id();
467 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
468 const VertexAttrib& info = attrib_infos_[ii];
469 DVLOG(1) << ii << ": loc = " << info.location
470 << ", size = " << info.size
471 << ", type = " << GLES2Util::GetStringEnum(info.type)
472 << ", name = " << info.name;
475 #endif
477 max_len = 0;
478 GLint num_uniforms = 0;
479 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
480 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
481 name_buffer.reset(new char[max_len]);
483 // Reads all the names.
484 std::vector<UniformData> uniform_data;
485 for (GLint ii = 0; ii < num_uniforms; ++ii) {
486 GLsizei length = 0;
487 UniformData data;
488 glGetActiveUniform(
489 service_id_, ii, max_len, &length,
490 &data.size, &data.type, name_buffer.get());
491 DCHECK(max_len == 0 || length < max_len);
492 DCHECK(length == 0 || name_buffer[length] == '\0');
493 data.queried_name = std::string(name_buffer.get());
494 GetCorrectedUniformData(data.queried_name, &data.corrected_name,
495 &data.original_name, &data.size, &data.type);
496 uniform_data.push_back(data);
499 // NOTE: We don't care if 2 uniforms are bound to the same location.
500 // One of them will take preference. The spec allows this, same as
501 // BindAttribLocation.
503 // The reason we don't check is if we were to fail we'd have to
504 // restore the previous program but since we've already linked successfully
505 // at this point the previous program is gone.
507 // Assigns the uniforms with bindings.
508 size_t next_available_index = 0;
509 for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
510 UniformData& data = uniform_data[ii];
511 // Force builtin uniforms (gl_DepthRange) to have invalid location.
512 if (ProgramManager::IsInvalidPrefix(data.queried_name.c_str(),
513 data.queried_name.size())) {
514 data.location = -1;
515 } else {
516 data.location =
517 glGetUniformLocation(service_id_, data.queried_name.c_str());
519 // remove "[0]"
520 std::string short_name;
521 int element_index = 0;
522 bool good = GetUniformNameSansElement(data.queried_name, &element_index,
523 &short_name);
524 DCHECK(good);
525 LocationMap::const_iterator it = bind_uniform_location_map_.find(
526 short_name);
527 if (it != bind_uniform_location_map_.end()) {
528 data.added = AddUniformInfo(
529 data.size, data.type, data.location, it->second, data.corrected_name,
530 data.original_name, &next_available_index);
534 // Assigns the uniforms that were not bound.
535 for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
536 const UniformData& data = uniform_data[ii];
537 if (!data.added) {
538 AddUniformInfo(
539 data.size, data.type, data.location, -1, data.corrected_name,
540 data.original_name, &next_available_index);
544 #if !defined(NDEBUG)
545 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
546 switches::kEnableGPUServiceLoggingGPU)) {
547 DVLOG(1) << "----: uniforms for service_id: " << service_id();
548 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
549 const UniformInfo& info = uniform_infos_[ii];
550 if (info.IsValid()) {
551 DVLOG(1) << ii << ": loc = " << info.element_locations[0]
552 << ", size = " << info.size
553 << ", type = " << GLES2Util::GetStringEnum(info.type)
554 << ", name = " << info.name;
558 #endif
560 valid_ = true;
563 void Program::ExecuteBindAttribLocationCalls() {
564 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
565 it != bind_attrib_location_map_.end(); ++it) {
566 const std::string* mapped_name = GetAttribMappedName(it->first);
567 if (mapped_name)
568 glBindAttribLocation(service_id_, it->second, mapped_name->c_str());
572 bool Program::Link(ShaderManager* manager,
573 Program::VaryingsPackingOption varyings_packing_option,
574 const ShaderCacheCallback& shader_callback) {
575 ClearLinkStatus();
577 if (!AttachedShadersExist()) {
578 set_log_info("missing shaders");
579 return false;
582 TimeTicks before_time = TimeTicks::Now();
583 bool link = true;
584 ProgramCache* cache = manager_->program_cache_;
585 if (cache) {
586 DCHECK(!attached_shaders_[0]->last_compiled_source().empty() &&
587 !attached_shaders_[1]->last_compiled_source().empty());
588 ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
589 attached_shaders_[0]->last_compiled_signature(),
590 attached_shaders_[1]->last_compiled_signature(),
591 &bind_attrib_location_map_,
592 transform_feedback_varyings_,
593 transform_feedback_buffer_mode_);
595 if (status == ProgramCache::LINK_SUCCEEDED) {
596 ProgramCache::ProgramLoadResult success =
597 cache->LoadLinkedProgram(service_id(),
598 attached_shaders_[0].get(),
599 attached_shaders_[1].get(),
600 &bind_attrib_location_map_,
601 transform_feedback_varyings_,
602 transform_feedback_buffer_mode_,
603 shader_callback);
604 link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
605 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
609 if (link) {
610 CompileAttachedShaders();
612 if (!CanLink()) {
613 set_log_info("invalid shaders");
614 return false;
616 if (DetectShaderVersionMismatch()) {
617 set_log_info("Versions of linked shaders have to match.");
618 return false;
620 if (DetectAttribLocationBindingConflicts()) {
621 set_log_info("glBindAttribLocation() conflicts");
622 return false;
624 std::string conflicting_name;
625 if (DetectUniformsMismatch(&conflicting_name)) {
626 std::string info_log = "Uniforms with the same name but different "
627 "type/precision: " + conflicting_name;
628 set_log_info(ProcessLogInfo(info_log).c_str());
629 return false;
631 if (DetectVaryingsMismatch(&conflicting_name)) {
632 std::string info_log = "Varyings with the same name but different type, "
633 "or statically used varyings in fragment shader "
634 "are not declared in vertex shader: " +
635 conflicting_name;
636 set_log_info(ProcessLogInfo(info_log).c_str());
637 return false;
639 if (DetectBuiltInInvariantConflicts()) {
640 set_log_info("Invariant settings for certain built-in varyings "
641 "have to match");
642 return false;
644 if (DetectGlobalNameConflicts(&conflicting_name)) {
645 std::string info_log = "Name conflicts between an uniform and an "
646 "attribute: " + conflicting_name;
647 set_log_info(ProcessLogInfo(info_log).c_str());
648 return false;
650 if (!CheckVaryingsPacking(varyings_packing_option)) {
651 set_log_info("Varyings over maximum register limit");
652 return false;
655 ExecuteBindAttribLocationCalls();
656 before_time = TimeTicks::Now();
657 if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
658 glProgramParameteri(service_id(),
659 PROGRAM_BINARY_RETRIEVABLE_HINT,
660 GL_TRUE);
662 glLinkProgram(service_id());
665 GLint success = 0;
666 glGetProgramiv(service_id(), GL_LINK_STATUS, &success);
667 if (success == GL_TRUE) {
668 Update();
669 if (link) {
670 if (cache) {
671 cache->SaveLinkedProgram(service_id(),
672 attached_shaders_[0].get(),
673 attached_shaders_[1].get(),
674 &bind_attrib_location_map_,
675 transform_feedback_varyings_,
676 transform_feedback_buffer_mode_,
677 shader_callback);
679 UMA_HISTOGRAM_CUSTOM_COUNTS(
680 "GPU.ProgramCache.BinaryCacheMissTime",
681 static_cast<base::HistogramBase::Sample>(
682 (TimeTicks::Now() - before_time).InMicroseconds()),
684 static_cast<base::HistogramBase::Sample>(
685 TimeDelta::FromSeconds(10).InMicroseconds()),
686 50);
687 } else {
688 UMA_HISTOGRAM_CUSTOM_COUNTS(
689 "GPU.ProgramCache.BinaryCacheHitTime",
690 static_cast<base::HistogramBase::Sample>(
691 (TimeTicks::Now() - before_time).InMicroseconds()),
693 static_cast<base::HistogramBase::Sample>(
694 TimeDelta::FromSeconds(1).InMicroseconds()),
695 50);
697 } else {
698 UpdateLogInfo();
700 return success == GL_TRUE;
703 void Program::Validate() {
704 if (!IsValid()) {
705 set_log_info("program not linked");
706 return;
708 glValidateProgram(service_id());
709 UpdateLogInfo();
712 GLint Program::GetUniformFakeLocation(
713 const std::string& name) const {
714 bool getting_array_location = false;
715 size_t open_pos = std::string::npos;
716 int index = 0;
717 if (!GLES2Util::ParseUniformName(
718 name, &open_pos, &index, &getting_array_location)) {
719 return -1;
721 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
722 const UniformInfo& info = uniform_infos_[ii];
723 if (!info.IsValid()) {
724 continue;
726 if (info.name == name ||
727 (info.is_array &&
728 info.name.compare(0, info.name.size() - 3, name) == 0)) {
729 return info.fake_location_base;
730 } else if (getting_array_location && info.is_array) {
731 // Look for an array specification.
732 size_t open_pos_2 = info.name.find_last_of('[');
733 if (open_pos_2 == open_pos &&
734 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
735 if (index >= 0 && index < info.size) {
736 DCHECK_GT(static_cast<int>(info.element_locations.size()), index);
737 if (info.element_locations[index] == -1)
738 return -1;
739 return ProgramManager::MakeFakeLocation(
740 info.fake_location_base, index);
745 return -1;
748 GLint Program::GetAttribLocation(
749 const std::string& original_name) const {
750 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
751 const VertexAttrib& info = attrib_infos_[ii];
752 if (info.name == original_name) {
753 return info.location;
756 return -1;
759 const Program::UniformInfo*
760 Program::GetUniformInfoByFakeLocation(
761 GLint fake_location, GLint* real_location, GLint* array_index) const {
762 DCHECK(real_location);
763 DCHECK(array_index);
764 if (fake_location < 0) {
765 return NULL;
768 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
769 if (uniform_index >= 0 &&
770 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
771 const UniformInfo& uniform_info = uniform_infos_[uniform_index];
772 if (!uniform_info.IsValid()) {
773 return NULL;
775 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
776 if (element_index < uniform_info.size) {
777 *real_location = uniform_info.element_locations[element_index];
778 *array_index = element_index;
779 return &uniform_info;
782 return NULL;
785 const std::string* Program::GetAttribMappedName(
786 const std::string& original_name) const {
787 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
788 Shader* shader = attached_shaders_[ii].get();
789 if (shader) {
790 const std::string* mapped_name =
791 shader->GetAttribMappedName(original_name);
792 if (mapped_name)
793 return mapped_name;
796 return NULL;
799 const std::string* Program::GetOriginalNameFromHashedName(
800 const std::string& hashed_name) const {
801 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
802 Shader* shader = attached_shaders_[ii].get();
803 if (shader) {
804 const std::string* original_name =
805 shader->GetOriginalNameFromHashedName(hashed_name);
806 if (original_name)
807 return original_name;
810 return NULL;
813 bool Program::SetUniformLocationBinding(
814 const std::string& name, GLint location) {
815 std::string short_name;
816 int element_index = 0;
817 if (!GetUniformNameSansElement(name, &element_index, &short_name) ||
818 element_index != 0) {
819 return false;
822 bind_uniform_location_map_[short_name] = location;
823 return true;
826 // Note: This is only valid to call right after a program has been linked
827 // successfully.
828 void Program::GetCorrectedUniformData(
829 const std::string& name,
830 std::string* corrected_name, std::string* original_name,
831 GLsizei* size, GLenum* type) const {
832 DCHECK(corrected_name && original_name && size && type);
833 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
834 Shader* shader = attached_shaders_[ii].get();
835 if (!shader)
836 continue;
837 const sh::ShaderVariable* info = NULL;
838 const sh::Uniform* uniform = shader->GetUniformInfo(name);
839 bool found = false;
840 if (uniform)
841 found = uniform->findInfoByMappedName(name, &info, original_name);
842 if (found) {
843 const std::string kArraySpec("[0]");
844 if (info->arraySize > 0 &&
845 !base::EndsWith(name, kArraySpec, base::CompareCase::SENSITIVE)) {
846 *corrected_name = name + kArraySpec;
847 *original_name += kArraySpec;
848 } else {
849 *corrected_name = name;
851 *type = info->type;
852 *size = std::max(1u, info->arraySize);
853 return;
856 // TODO(zmo): this path should never be reached unless there is a serious
857 // bug in the driver or in ANGLE translator.
858 *corrected_name = name;
859 *original_name = name;
862 void Program::GetVertexAttribData(
863 const std::string& name, std::string* original_name, GLenum* type) const {
864 DCHECK(original_name);
865 DCHECK(type);
866 Shader* shader = attached_shaders_[ShaderTypeToIndex(GL_VERTEX_SHADER)].get();
867 if (shader) {
868 // Vertex attributes can not be arrays or structs (GLSL ES 3.00.4, section
869 // 4.3.4, "Input Variables"), so the top level sh::Attribute returns the
870 // information we need.
871 const sh::Attribute* info = shader->GetAttribInfo(name);
872 if (info) {
873 *original_name = info->name;
874 *type = info->type;
875 return;
878 // TODO(zmo): this path should never be reached unless there is a serious
879 // bug in the driver or in ANGLE translator.
880 *original_name = name;
883 bool Program::AddUniformInfo(
884 GLsizei size, GLenum type, GLint location, GLint fake_base_location,
885 const std::string& name, const std::string& original_name,
886 size_t* next_available_index) {
887 DCHECK(next_available_index);
888 const char* kArraySpec = "[0]";
889 size_t uniform_index =
890 fake_base_location >= 0 ? fake_base_location : *next_available_index;
891 if (uniform_infos_.size() < uniform_index + 1) {
892 uniform_infos_.resize(uniform_index + 1);
895 // return if this location is already in use.
896 if (uniform_infos_[uniform_index].IsValid()) {
897 DCHECK_GE(fake_base_location, 0);
898 return false;
901 uniform_infos_[uniform_index] = UniformInfo(
902 size, type, uniform_index, original_name);
903 ++num_uniforms_;
905 UniformInfo& info = uniform_infos_[uniform_index];
906 info.element_locations.resize(size);
907 info.element_locations[0] = location;
908 DCHECK_GE(size, 0);
909 size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
910 info.texture_units.clear();
911 info.texture_units.resize(num_texture_units, 0);
913 if (size > 1) {
914 // Go through the array element locations looking for a match.
915 // We can skip the first element because it's the same as the
916 // the location without the array operators.
917 size_t array_pos = name.rfind(kArraySpec);
918 std::string base_name = name;
919 if (name.size() > 3) {
920 if (array_pos != name.size() - 3) {
921 info.name = name + kArraySpec;
922 } else {
923 base_name = name.substr(0, name.size() - 3);
926 for (GLsizei ii = 1; ii < info.size; ++ii) {
927 std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
928 info.element_locations[ii] =
929 glGetUniformLocation(service_id_, element_name.c_str());
933 info.is_array =
934 (size > 1 ||
935 (info.name.size() > 3 &&
936 info.name.rfind(kArraySpec) == info.name.size() - 3));
938 if (info.IsSampler()) {
939 sampler_indices_.push_back(info.fake_location_base);
941 max_uniform_name_length_ =
942 std::max(max_uniform_name_length_,
943 static_cast<GLsizei>(info.name.size()));
945 while (*next_available_index < uniform_infos_.size() &&
946 uniform_infos_[*next_available_index].IsValid()) {
947 *next_available_index = *next_available_index + 1;
950 return true;
953 const Program::UniformInfo*
954 Program::GetUniformInfo(
955 GLint index) const {
956 if (static_cast<size_t>(index) >= uniform_infos_.size()) {
957 return NULL;
960 const UniformInfo& info = uniform_infos_[index];
961 return info.IsValid() ? &info : NULL;
964 bool Program::SetSamplers(
965 GLint num_texture_units, GLint fake_location,
966 GLsizei count, const GLint* value) {
967 if (fake_location < 0) {
968 return true;
970 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
971 if (uniform_index >= 0 &&
972 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
973 UniformInfo& info = uniform_infos_[uniform_index];
974 if (!info.IsValid()) {
975 return false;
977 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
978 if (element_index < info.size) {
979 count = std::min(info.size - element_index, count);
980 if (info.IsSampler() && count > 0) {
981 for (GLsizei ii = 0; ii < count; ++ii) {
982 if (value[ii] < 0 || value[ii] >= num_texture_units) {
983 return false;
986 std::copy(value, value + count,
987 info.texture_units.begin() + element_index);
988 return true;
992 return true;
995 void Program::GetProgramiv(GLenum pname, GLint* params) {
996 switch (pname) {
997 case GL_ACTIVE_ATTRIBUTES:
998 *params = attrib_infos_.size();
999 break;
1000 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
1001 // Notice +1 to accomodate NULL terminator.
1002 *params = max_attrib_name_length_ + 1;
1003 break;
1004 case GL_ACTIVE_UNIFORMS:
1005 *params = num_uniforms_;
1006 break;
1007 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
1008 // Notice +1 to accomodate NULL terminator.
1009 *params = max_uniform_name_length_ + 1;
1010 break;
1011 case GL_LINK_STATUS:
1012 *params = link_status_;
1013 break;
1014 case GL_INFO_LOG_LENGTH:
1015 // Notice +1 to accomodate NULL terminator.
1016 *params = log_info_.get() ? (log_info_->size() + 1) : 0;
1017 break;
1018 case GL_DELETE_STATUS:
1019 *params = deleted_;
1020 break;
1021 case GL_VALIDATE_STATUS:
1022 if (!IsValid()) {
1023 *params = GL_FALSE;
1024 } else {
1025 glGetProgramiv(service_id_, pname, params);
1027 break;
1028 default:
1029 glGetProgramiv(service_id_, pname, params);
1030 break;
1034 bool Program::AttachShader(
1035 ShaderManager* shader_manager,
1036 Shader* shader) {
1037 DCHECK(shader_manager);
1038 DCHECK(shader);
1039 int index = ShaderTypeToIndex(shader->shader_type());
1040 if (attached_shaders_[index].get() != NULL) {
1041 return false;
1043 attached_shaders_[index] = scoped_refptr<Shader>(shader);
1044 shader_manager->UseShader(shader);
1045 return true;
1048 bool Program::DetachShader(
1049 ShaderManager* shader_manager,
1050 Shader* shader) {
1051 DCHECK(shader_manager);
1052 DCHECK(shader);
1053 if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() !=
1054 shader) {
1055 return false;
1057 attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL;
1058 shader_manager->UnuseShader(shader);
1059 return true;
1062 void Program::DetachShaders(ShaderManager* shader_manager) {
1063 DCHECK(shader_manager);
1064 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1065 if (attached_shaders_[ii].get()) {
1066 DetachShader(shader_manager, attached_shaders_[ii].get());
1071 void Program::CompileAttachedShaders() {
1072 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1073 Shader* shader = attached_shaders_[ii].get();
1074 if (shader) {
1075 shader->DoCompile();
1080 bool Program::AttachedShadersExist() const {
1081 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1082 if (!attached_shaders_[ii].get())
1083 return false;
1085 return true;
1088 bool Program::CanLink() const {
1089 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1090 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid()) {
1091 return false;
1094 return true;
1097 bool Program::DetectShaderVersionMismatch() const {
1098 int version = Shader::kUndefinedShaderVersion;
1099 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1100 Shader* shader = attached_shaders_[ii].get();
1101 if (shader) {
1102 if (version != Shader::kUndefinedShaderVersion &&
1103 shader->shader_version() != version) {
1104 return true;
1106 version = shader->shader_version();
1107 DCHECK(version != Shader::kUndefinedShaderVersion);
1110 return false;
1113 bool Program::DetectAttribLocationBindingConflicts() const {
1114 std::set<GLint> location_binding_used;
1115 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
1116 it != bind_attrib_location_map_.end(); ++it) {
1117 // Find out if an attribute is statically used in this program's shaders.
1118 const sh::Attribute* attrib = NULL;
1119 const std::string* mapped_name = GetAttribMappedName(it->first);
1120 if (!mapped_name)
1121 continue;
1122 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1123 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid())
1124 continue;
1125 attrib = attached_shaders_[ii]->GetAttribInfo(*mapped_name);
1126 if (attrib) {
1127 if (attrib->staticUse)
1128 break;
1129 else
1130 attrib = NULL;
1133 if (attrib) {
1134 size_t num_of_locations = 1;
1135 switch (attrib->type) {
1136 case GL_FLOAT_MAT2:
1137 num_of_locations = 2;
1138 break;
1139 case GL_FLOAT_MAT3:
1140 num_of_locations = 3;
1141 break;
1142 case GL_FLOAT_MAT4:
1143 num_of_locations = 4;
1144 break;
1145 default:
1146 break;
1148 for (size_t ii = 0; ii < num_of_locations; ++ii) {
1149 GLint loc = it->second + ii;
1150 std::pair<std::set<GLint>::iterator, bool> result =
1151 location_binding_used.insert(loc);
1152 if (!result.second)
1153 return true;
1157 return false;
1160 bool Program::DetectUniformsMismatch(std::string* conflicting_name) const {
1161 typedef std::map<std::string, const sh::Uniform*> UniformPointerMap;
1162 UniformPointerMap uniform_pointer_map;
1163 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1164 const UniformMap& shader_uniforms = attached_shaders_[ii]->uniform_map();
1165 for (UniformMap::const_iterator iter = shader_uniforms.begin();
1166 iter != shader_uniforms.end(); ++iter) {
1167 const std::string& name = iter->first;
1168 UniformPointerMap::iterator hit = uniform_pointer_map.find(name);
1169 if (hit == uniform_pointer_map.end()) {
1170 uniform_pointer_map[name] = &(iter->second);
1171 } else {
1172 // If a uniform is in the map, i.e., it has already been declared by
1173 // another shader, then the type, precision, etc. must match.
1174 if (hit->second->isSameUniformAtLinkTime(iter->second))
1175 continue;
1176 *conflicting_name = name;
1177 return true;
1181 return false;
1184 bool Program::DetectVaryingsMismatch(std::string* conflicting_name) const {
1185 DCHECK(attached_shaders_[0].get() &&
1186 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1187 attached_shaders_[1].get() &&
1188 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1189 const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
1190 const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
1192 int shader_version = attached_shaders_[0]->shader_version();
1194 for (VaryingMap::const_iterator iter = fragment_varyings->begin();
1195 iter != fragment_varyings->end(); ++iter) {
1196 const std::string& name = iter->first;
1197 if (IsBuiltInFragmentVarying(name))
1198 continue;
1200 VaryingMap::const_iterator hit = vertex_varyings->find(name);
1201 if (hit == vertex_varyings->end()) {
1202 if (iter->second.staticUse) {
1203 *conflicting_name = name;
1204 return true;
1206 continue;
1209 if (!hit->second.isSameVaryingAtLinkTime(iter->second, shader_version)) {
1210 *conflicting_name = name;
1211 return true;
1215 return false;
1218 bool Program::DetectBuiltInInvariantConflicts() const {
1219 DCHECK(attached_shaders_[0].get() &&
1220 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1221 attached_shaders_[1].get() &&
1222 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1223 const VaryingMap& vertex_varyings = attached_shaders_[0]->varying_map();
1224 const VaryingMap& fragment_varyings = attached_shaders_[1]->varying_map();
1226 bool gl_position_invariant = IsBuiltInInvariant(
1227 vertex_varyings, "gl_Position");
1228 bool gl_point_size_invariant = IsBuiltInInvariant(
1229 vertex_varyings, "gl_PointSize");
1231 bool gl_frag_coord_invariant = IsBuiltInInvariant(
1232 fragment_varyings, "gl_FragCoord");
1233 bool gl_point_coord_invariant = IsBuiltInInvariant(
1234 fragment_varyings, "gl_PointCoord");
1236 return ((gl_frag_coord_invariant && !gl_position_invariant) ||
1237 (gl_point_coord_invariant && !gl_point_size_invariant));
1240 bool Program::DetectGlobalNameConflicts(std::string* conflicting_name) const {
1241 DCHECK(attached_shaders_[0].get() &&
1242 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1243 attached_shaders_[1].get() &&
1244 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1245 const UniformMap* uniforms[2];
1246 uniforms[0] = &(attached_shaders_[0]->uniform_map());
1247 uniforms[1] = &(attached_shaders_[1]->uniform_map());
1248 const AttributeMap* attribs =
1249 &(attached_shaders_[0]->attrib_map());
1251 for (AttributeMap::const_iterator iter = attribs->begin();
1252 iter != attribs->end(); ++iter) {
1253 for (int ii = 0; ii < 2; ++ii) {
1254 if (uniforms[ii]->find(iter->first) != uniforms[ii]->end()) {
1255 *conflicting_name = iter->first;
1256 return true;
1260 return false;
1263 bool Program::CheckVaryingsPacking(
1264 Program::VaryingsPackingOption option) const {
1265 DCHECK(attached_shaders_[0].get() &&
1266 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1267 attached_shaders_[1].get() &&
1268 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1269 const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
1270 const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
1272 std::map<std::string, ShVariableInfo> combined_map;
1274 for (VaryingMap::const_iterator iter = fragment_varyings->begin();
1275 iter != fragment_varyings->end(); ++iter) {
1276 if (!iter->second.staticUse && option == kCountOnlyStaticallyUsed)
1277 continue;
1278 if (!IsBuiltInFragmentVarying(iter->first)) {
1279 VaryingMap::const_iterator vertex_iter =
1280 vertex_varyings->find(iter->first);
1281 if (vertex_iter == vertex_varyings->end() ||
1282 (!vertex_iter->second.staticUse &&
1283 option == kCountOnlyStaticallyUsed))
1284 continue;
1287 ShVariableInfo var;
1288 var.type = static_cast<sh::GLenum>(iter->second.type);
1289 var.size = std::max(1u, iter->second.arraySize);
1290 combined_map[iter->first] = var;
1293 if (combined_map.size() == 0)
1294 return true;
1295 scoped_ptr<ShVariableInfo[]> variables(
1296 new ShVariableInfo[combined_map.size()]);
1297 size_t index = 0;
1298 for (std::map<std::string, ShVariableInfo>::const_iterator iter =
1299 combined_map.begin();
1300 iter != combined_map.end(); ++iter) {
1301 variables[index].type = iter->second.type;
1302 variables[index].size = iter->second.size;
1303 ++index;
1305 return ShCheckVariablesWithinPackingLimits(
1306 static_cast<int>(manager_->max_varying_vectors()),
1307 variables.get(),
1308 combined_map.size());
1311 void Program::GetProgramInfo(
1312 ProgramManager* manager, CommonDecoder::Bucket* bucket) const {
1313 // NOTE: It seems to me the math in here does not need check for overflow
1314 // because the data being calucated from has various small limits. The max
1315 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1316 // of an identifier is 256 characters.
1317 uint32 num_locations = 0;
1318 uint32 total_string_size = 0;
1320 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1321 const VertexAttrib& info = attrib_infos_[ii];
1322 num_locations += 1;
1323 total_string_size += info.name.size();
1326 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1327 const UniformInfo& info = uniform_infos_[ii];
1328 if (info.IsValid()) {
1329 num_locations += info.element_locations.size();
1330 total_string_size += info.name.size();
1334 uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
1335 uint32 input_size = num_inputs * sizeof(ProgramInput);
1336 uint32 location_size = num_locations * sizeof(int32);
1337 uint32 size = sizeof(ProgramInfoHeader) +
1338 input_size + location_size + total_string_size;
1340 bucket->SetSize(size);
1341 ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
1342 ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
1343 sizeof(ProgramInfoHeader), input_size);
1344 int32* locations = bucket->GetDataAs<int32*>(
1345 sizeof(ProgramInfoHeader) + input_size, location_size);
1346 char* strings = bucket->GetDataAs<char*>(
1347 sizeof(ProgramInfoHeader) + input_size + location_size,
1348 total_string_size);
1349 DCHECK(header);
1350 DCHECK(inputs);
1351 DCHECK(locations);
1352 DCHECK(strings);
1354 header->link_status = link_status_;
1355 header->num_attribs = attrib_infos_.size();
1356 header->num_uniforms = num_uniforms_;
1358 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1359 const VertexAttrib& info = attrib_infos_[ii];
1360 inputs->size = info.size;
1361 inputs->type = info.type;
1362 inputs->location_offset = ComputeOffset(header, locations);
1363 inputs->name_offset = ComputeOffset(header, strings);
1364 inputs->name_length = info.name.size();
1365 *locations++ = info.location;
1366 memcpy(strings, info.name.c_str(), info.name.size());
1367 strings += info.name.size();
1368 ++inputs;
1371 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1372 const UniformInfo& info = uniform_infos_[ii];
1373 if (info.IsValid()) {
1374 inputs->size = info.size;
1375 inputs->type = info.type;
1376 inputs->location_offset = ComputeOffset(header, locations);
1377 inputs->name_offset = ComputeOffset(header, strings);
1378 inputs->name_length = info.name.size();
1379 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
1380 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
1381 if (info.element_locations[jj] == -1)
1382 *locations++ = -1;
1383 else
1384 *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
1386 memcpy(strings, info.name.c_str(), info.name.size());
1387 strings += info.name.size();
1388 ++inputs;
1392 DCHECK_EQ(ComputeOffset(header, strings), size);
1395 bool Program::GetUniformBlocks(CommonDecoder::Bucket* bucket) const {
1396 // The data is packed into the bucket in the following order
1397 // 1) header
1398 // 2) N entries of block data (except for name and indices)
1399 // 3) name1, indices1, name2, indices2, ..., nameN, indicesN
1401 // We query all the data directly through GL calls, assuming they are
1402 // cheap through MANGLE.
1404 DCHECK(bucket);
1405 GLuint program = service_id();
1407 uint32_t header_size = sizeof(UniformBlocksHeader);
1408 bucket->SetSize(header_size); // In case we fail.
1410 uint32_t num_uniform_blocks = 0;
1411 GLint param = GL_FALSE;
1412 // We assume program is a valid program service id.
1413 glGetProgramiv(program, GL_LINK_STATUS, &param);
1414 if (param == GL_TRUE) {
1415 param = 0;
1416 glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &param);
1417 num_uniform_blocks = static_cast<uint32_t>(param);
1419 if (num_uniform_blocks == 0) {
1420 // Although spec allows an implementation to return uniform block info
1421 // even if a link fails, for consistency, we disallow that.
1422 return true;
1425 std::vector<UniformBlockInfo> blocks(num_uniform_blocks);
1426 base::CheckedNumeric<uint32_t> size = sizeof(UniformBlockInfo);
1427 size *= num_uniform_blocks;
1428 uint32_t entry_size = size.ValueOrDefault(0);
1429 size += header_size;
1430 std::vector<std::string> names(num_uniform_blocks);
1431 GLint max_name_length = 0;
1432 glGetProgramiv(
1433 program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_name_length);
1434 std::vector<GLchar> buffer(max_name_length);
1435 GLsizei length;
1436 for (uint32_t ii = 0; ii < num_uniform_blocks; ++ii) {
1437 param = 0;
1438 glGetActiveUniformBlockiv(program, ii, GL_UNIFORM_BLOCK_BINDING, &param);
1439 blocks[ii].binding = static_cast<uint32_t>(param);
1441 param = 0;
1442 glGetActiveUniformBlockiv(program, ii, GL_UNIFORM_BLOCK_DATA_SIZE, &param);
1443 blocks[ii].data_size = static_cast<uint32_t>(param);
1445 blocks[ii].name_offset = size.ValueOrDefault(0);
1446 param = 0;
1447 glGetActiveUniformBlockiv(
1448 program, ii, GL_UNIFORM_BLOCK_NAME_LENGTH, &param);
1449 DCHECK_GE(max_name_length, param);
1450 memset(&buffer[0], 0, param);
1451 length = 0;
1452 glGetActiveUniformBlockName(
1453 program, ii, static_cast<GLsizei>(param), &length, &buffer[0]);
1454 DCHECK_EQ(param, length + 1);
1455 names[ii] = std::string(&buffer[0], length);
1456 // TODO(zmo): optimize the name mapping lookup.
1457 const std::string* original_name = GetOriginalNameFromHashedName(names[ii]);
1458 if (original_name)
1459 names[ii] = *original_name;
1460 blocks[ii].name_length = names[ii].size() + 1;
1461 size += blocks[ii].name_length;
1463 param = 0;
1464 glGetActiveUniformBlockiv(
1465 program, ii, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &param);
1466 blocks[ii].active_uniforms = static_cast<uint32_t>(param);
1467 blocks[ii].active_uniform_offset = size.ValueOrDefault(0);
1468 base::CheckedNumeric<uint32_t> indices_size = blocks[ii].active_uniforms;
1469 indices_size *= sizeof(uint32_t);
1470 if (!indices_size.IsValid())
1471 return false;
1472 size += indices_size.ValueOrDefault(0);
1474 param = 0;
1475 glGetActiveUniformBlockiv(
1476 program, ii, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &param);
1477 blocks[ii].referenced_by_vertex_shader = static_cast<uint32_t>(param);
1479 param = 0;
1480 glGetActiveUniformBlockiv(
1481 program, ii, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &param);
1482 blocks[ii].referenced_by_fragment_shader = static_cast<uint32_t>(param);
1484 if (!size.IsValid())
1485 return false;
1486 uint32_t total_size = size.ValueOrDefault(0);
1487 DCHECK_LE(header_size + entry_size, total_size);
1488 uint32_t data_size = total_size - header_size - entry_size;
1490 bucket->SetSize(total_size);
1491 UniformBlocksHeader* header =
1492 bucket->GetDataAs<UniformBlocksHeader*>(0, header_size);
1493 UniformBlockInfo* entries = bucket->GetDataAs<UniformBlockInfo*>(
1494 header_size, entry_size);
1495 char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size);
1496 DCHECK(header);
1497 DCHECK(entries);
1498 DCHECK(data);
1500 // Copy over data for the header and entries.
1501 header->num_uniform_blocks = num_uniform_blocks;
1502 memcpy(entries, &blocks[0], entry_size);
1504 std::vector<GLint> params;
1505 for (uint32_t ii = 0; ii < num_uniform_blocks; ++ii) {
1506 // Get active uniform name.
1507 memcpy(data, names[ii].c_str(), names[ii].length() + 1);
1508 data += names[ii].length() + 1;
1510 // Get active uniform indices.
1511 if (params.size() < blocks[ii].active_uniforms)
1512 params.resize(blocks[ii].active_uniforms);
1513 uint32_t num_bytes = blocks[ii].active_uniforms * sizeof(GLint);
1514 memset(&params[0], 0, num_bytes);
1515 glGetActiveUniformBlockiv(
1516 program, ii, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, &params[0]);
1517 uint32_t* indices = reinterpret_cast<uint32_t*>(data);
1518 for (uint32_t uu = 0; uu < blocks[ii].active_uniforms; ++uu) {
1519 indices[uu] = static_cast<uint32_t>(params[uu]);
1521 data += num_bytes;
1523 DCHECK_EQ(ComputeOffset(header, data), total_size);
1524 return true;
1527 bool Program::GetTransformFeedbackVaryings(
1528 CommonDecoder::Bucket* bucket) const {
1529 // The data is packed into the bucket in the following order
1530 // 1) header
1531 // 2) N entries of varying data (except for name)
1532 // 3) name1, name2, ..., nameN
1534 // We query all the data directly through GL calls, assuming they are
1535 // cheap through MANGLE.
1537 DCHECK(bucket);
1538 GLuint program = service_id();
1540 uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader);
1541 bucket->SetSize(header_size); // In case we fail.
1543 uint32_t num_transform_feedback_varyings = 0;
1544 GLint param = GL_FALSE;
1545 // We assume program is a valid program service id.
1546 glGetProgramiv(program, GL_LINK_STATUS, &param);
1547 if (param == GL_TRUE) {
1548 param = 0;
1549 glGetProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &param);
1550 num_transform_feedback_varyings = static_cast<uint32_t>(param);
1552 if (num_transform_feedback_varyings == 0) {
1553 return true;
1556 std::vector<TransformFeedbackVaryingInfo> varyings(
1557 num_transform_feedback_varyings);
1558 base::CheckedNumeric<uint32_t> size = sizeof(TransformFeedbackVaryingInfo);
1559 size *= num_transform_feedback_varyings;
1560 uint32_t entry_size = size.ValueOrDefault(0);
1561 size += header_size;
1562 std::vector<std::string> names(num_transform_feedback_varyings);
1563 GLint max_name_length = 0;
1564 glGetProgramiv(
1565 program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &max_name_length);
1566 if (max_name_length < 1)
1567 max_name_length = 1;
1568 std::vector<char> buffer(max_name_length);
1569 for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) {
1570 GLsizei var_size = 0;
1571 GLsizei var_name_length = 0;
1572 GLenum var_type = 0;
1573 glGetTransformFeedbackVarying(
1574 program, ii, max_name_length,
1575 &var_name_length, &var_size, &var_type, &buffer[0]);
1576 varyings[ii].size = static_cast<uint32_t>(var_size);
1577 varyings[ii].type = static_cast<uint32_t>(var_type);
1578 varyings[ii].name_offset = static_cast<uint32_t>(size.ValueOrDefault(0));
1579 DCHECK_GT(max_name_length, var_name_length);
1580 names[ii] = std::string(&buffer[0], var_name_length);
1581 // TODO(zmo): optimize the name mapping lookup.
1582 const std::string* original_name = GetOriginalNameFromHashedName(names[ii]);
1583 if (original_name)
1584 names[ii] = *original_name;
1585 varyings[ii].name_length = names[ii].size() + 1;
1586 size += names[ii].size();
1587 size += 1;
1589 if (!size.IsValid())
1590 return false;
1591 uint32_t total_size = size.ValueOrDefault(0);
1592 DCHECK_LE(header_size + entry_size, total_size);
1593 uint32_t data_size = total_size - header_size - entry_size;
1595 bucket->SetSize(total_size);
1596 TransformFeedbackVaryingsHeader* header =
1597 bucket->GetDataAs<TransformFeedbackVaryingsHeader*>(0, header_size);
1598 TransformFeedbackVaryingInfo* entries =
1599 bucket->GetDataAs<TransformFeedbackVaryingInfo*>(header_size, entry_size);
1600 char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size);
1601 DCHECK(header);
1602 DCHECK(entries);
1603 DCHECK(data);
1605 // Copy over data for the header and entries.
1606 header->num_transform_feedback_varyings = num_transform_feedback_varyings;
1607 memcpy(entries, &varyings[0], entry_size);
1609 for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) {
1610 memcpy(data, names[ii].c_str(), names[ii].length() + 1);
1611 data += names[ii].length() + 1;
1613 DCHECK_EQ(ComputeOffset(header, data), total_size);
1614 return true;
1617 bool Program::GetUniformsES3(CommonDecoder::Bucket* bucket) const {
1618 // The data is packed into the bucket in the following order
1619 // 1) header
1620 // 2) N entries of UniformES3Info
1622 // We query all the data directly through GL calls, assuming they are
1623 // cheap through MANGLE.
1625 DCHECK(bucket);
1626 GLuint program = service_id();
1628 uint32_t header_size = sizeof(UniformsES3Header);
1629 bucket->SetSize(header_size); // In case we fail.
1631 GLsizei count = 0;
1632 GLint param = GL_FALSE;
1633 // We assume program is a valid program service id.
1634 glGetProgramiv(program, GL_LINK_STATUS, &param);
1635 if (param == GL_TRUE) {
1636 param = 0;
1637 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count);
1639 if (count == 0) {
1640 return true;
1643 base::CheckedNumeric<uint32_t> size = sizeof(UniformES3Info);
1644 size *= count;
1645 uint32_t entry_size = size.ValueOrDefault(0);
1646 size += header_size;
1647 if (!size.IsValid())
1648 return false;
1649 uint32_t total_size = size.ValueOrDefault(0);
1650 bucket->SetSize(total_size);
1651 UniformsES3Header* header =
1652 bucket->GetDataAs<UniformsES3Header*>(0, header_size);
1653 DCHECK(header);
1654 header->num_uniforms = static_cast<uint32_t>(count);
1656 // Instead of GetDataAs<UniformES3Info*>, we do GetDataAs<int32_t>. This is
1657 // because struct UniformES3Info is defined as five int32_t.
1658 // By doing this, we can fill the structs through loops.
1659 int32_t* entries =
1660 bucket->GetDataAs<int32_t*>(header_size, entry_size);
1661 DCHECK(entries);
1662 const size_t kStride = sizeof(UniformES3Info) / sizeof(int32_t);
1664 const GLenum kPname[] = {
1665 GL_UNIFORM_BLOCK_INDEX,
1666 GL_UNIFORM_OFFSET,
1667 GL_UNIFORM_ARRAY_STRIDE,
1668 GL_UNIFORM_MATRIX_STRIDE,
1669 GL_UNIFORM_IS_ROW_MAJOR,
1671 const GLint kDefaultValue[] = { -1, -1, -1, -1, 0 };
1672 const size_t kNumPnames = arraysize(kPname);
1673 std::vector<GLuint> indices(count);
1674 for (GLsizei ii = 0; ii < count; ++ii) {
1675 indices[ii] = ii;
1677 std::vector<GLint> params(count);
1678 for (size_t pname_index = 0; pname_index < kNumPnames; ++pname_index) {
1679 for (GLsizei ii = 0; ii < count; ++ii) {
1680 params[ii] = kDefaultValue[pname_index];
1682 glGetActiveUniformsiv(
1683 program, count, &indices[0], kPname[pname_index], &params[0]);
1684 for (GLsizei ii = 0; ii < count; ++ii) {
1685 entries[kStride * ii + pname_index] = params[ii];
1688 return true;
1691 void Program::TransformFeedbackVaryings(GLsizei count,
1692 const char* const* varyings,
1693 GLenum buffer_mode) {
1694 transform_feedback_varyings_.clear();
1695 for (GLsizei i = 0; i < count; ++i) {
1696 transform_feedback_varyings_.push_back(std::string(varyings[i]));
1698 transform_feedback_buffer_mode_ = buffer_mode;
1701 Program::~Program() {
1702 if (manager_) {
1703 if (manager_->have_context_) {
1704 glDeleteProgram(service_id());
1706 manager_->StopTracking(this);
1707 manager_ = NULL;
1712 ProgramManager::ProgramManager(ProgramCache* program_cache,
1713 uint32 max_varying_vectors)
1714 : program_count_(0),
1715 have_context_(true),
1716 program_cache_(program_cache),
1717 max_varying_vectors_(max_varying_vectors) { }
1719 ProgramManager::~ProgramManager() {
1720 DCHECK(programs_.empty());
1723 void ProgramManager::Destroy(bool have_context) {
1724 have_context_ = have_context;
1725 programs_.clear();
1728 void ProgramManager::StartTracking(Program* /* program */) {
1729 ++program_count_;
1732 void ProgramManager::StopTracking(Program* /* program */) {
1733 --program_count_;
1736 Program* ProgramManager::CreateProgram(
1737 GLuint client_id, GLuint service_id) {
1738 std::pair<ProgramMap::iterator, bool> result =
1739 programs_.insert(
1740 std::make_pair(client_id,
1741 scoped_refptr<Program>(
1742 new Program(this, service_id))));
1743 DCHECK(result.second);
1744 return result.first->second.get();
1747 Program* ProgramManager::GetProgram(GLuint client_id) {
1748 ProgramMap::iterator it = programs_.find(client_id);
1749 return it != programs_.end() ? it->second.get() : NULL;
1752 bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
1753 // This doesn't need to be fast. It's only used during slow queries.
1754 for (ProgramMap::const_iterator it = programs_.begin();
1755 it != programs_.end(); ++it) {
1756 if (it->second->service_id() == service_id) {
1757 *client_id = it->first;
1758 return true;
1761 return false;
1764 ProgramCache* ProgramManager::program_cache() const {
1765 return program_cache_;
1768 bool ProgramManager::IsOwned(Program* program) {
1769 for (ProgramMap::iterator it = programs_.begin();
1770 it != programs_.end(); ++it) {
1771 if (it->second.get() == program) {
1772 return true;
1775 return false;
1778 void ProgramManager::RemoveProgramInfoIfUnused(
1779 ShaderManager* shader_manager, Program* program) {
1780 DCHECK(shader_manager);
1781 DCHECK(program);
1782 DCHECK(IsOwned(program));
1783 if (program->IsDeleted() && !program->InUse()) {
1784 program->DetachShaders(shader_manager);
1785 for (ProgramMap::iterator it = programs_.begin();
1786 it != programs_.end(); ++it) {
1787 if (it->second.get() == program) {
1788 programs_.erase(it);
1789 return;
1792 NOTREACHED();
1796 void ProgramManager::MarkAsDeleted(
1797 ShaderManager* shader_manager,
1798 Program* program) {
1799 DCHECK(shader_manager);
1800 DCHECK(program);
1801 DCHECK(IsOwned(program));
1802 program->MarkAsDeleted();
1803 RemoveProgramInfoIfUnused(shader_manager, program);
1806 void ProgramManager::UseProgram(Program* program) {
1807 DCHECK(program);
1808 DCHECK(IsOwned(program));
1809 program->IncUseCount();
1812 void ProgramManager::UnuseProgram(
1813 ShaderManager* shader_manager,
1814 Program* program) {
1815 DCHECK(shader_manager);
1816 DCHECK(program);
1817 DCHECK(IsOwned(program));
1818 program->DecUseCount();
1819 RemoveProgramInfoIfUnused(shader_manager, program);
1822 void ProgramManager::ClearUniforms(Program* program) {
1823 DCHECK(program);
1824 program->ClearUniforms(&zero_);
1827 int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
1828 return index + element * 0x10000;
1831 } // namespace gles2
1832 } // namespace gpu