[MacViews] Show comboboxes with a native NSMenu
[chromium-blink-merge.git] / gpu / command_buffer / service / program_manager.cc
blob904a5680ca5db6b746d659f04ebf02014ecd04af
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 bool cache_hit = status == ProgramCache::LINK_SUCCEEDED;
596 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.CacheHit", cache_hit);
598 if (cache_hit) {
599 ProgramCache::ProgramLoadResult success =
600 cache->LoadLinkedProgram(service_id(),
601 attached_shaders_[0].get(),
602 attached_shaders_[1].get(),
603 &bind_attrib_location_map_,
604 transform_feedback_varyings_,
605 transform_feedback_buffer_mode_,
606 shader_callback);
607 link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
608 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
612 if (link) {
613 CompileAttachedShaders();
615 if (!CanLink()) {
616 set_log_info("invalid shaders");
617 return false;
619 if (DetectShaderVersionMismatch()) {
620 set_log_info("Versions of linked shaders have to match.");
621 return false;
623 if (DetectAttribLocationBindingConflicts()) {
624 set_log_info("glBindAttribLocation() conflicts");
625 return false;
627 std::string conflicting_name;
628 if (DetectUniformsMismatch(&conflicting_name)) {
629 std::string info_log = "Uniforms with the same name but different "
630 "type/precision: " + conflicting_name;
631 set_log_info(ProcessLogInfo(info_log).c_str());
632 return false;
634 if (DetectVaryingsMismatch(&conflicting_name)) {
635 std::string info_log = "Varyings with the same name but different type, "
636 "or statically used varyings in fragment shader "
637 "are not declared in vertex shader: " +
638 conflicting_name;
639 set_log_info(ProcessLogInfo(info_log).c_str());
640 return false;
642 if (DetectBuiltInInvariantConflicts()) {
643 set_log_info("Invariant settings for certain built-in varyings "
644 "have to match");
645 return false;
647 if (DetectGlobalNameConflicts(&conflicting_name)) {
648 std::string info_log = "Name conflicts between an uniform and an "
649 "attribute: " + conflicting_name;
650 set_log_info(ProcessLogInfo(info_log).c_str());
651 return false;
653 if (!CheckVaryingsPacking(varyings_packing_option)) {
654 set_log_info("Varyings over maximum register limit");
655 return false;
658 ExecuteBindAttribLocationCalls();
659 before_time = TimeTicks::Now();
660 if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
661 glProgramParameteri(service_id(),
662 PROGRAM_BINARY_RETRIEVABLE_HINT,
663 GL_TRUE);
665 glLinkProgram(service_id());
668 GLint success = 0;
669 glGetProgramiv(service_id(), GL_LINK_STATUS, &success);
670 if (success == GL_TRUE) {
671 Update();
672 if (link) {
673 if (cache) {
674 cache->SaveLinkedProgram(service_id(),
675 attached_shaders_[0].get(),
676 attached_shaders_[1].get(),
677 &bind_attrib_location_map_,
678 transform_feedback_varyings_,
679 transform_feedback_buffer_mode_,
680 shader_callback);
682 UMA_HISTOGRAM_CUSTOM_COUNTS(
683 "GPU.ProgramCache.BinaryCacheMissTime",
684 static_cast<base::HistogramBase::Sample>(
685 (TimeTicks::Now() - before_time).InMicroseconds()),
687 static_cast<base::HistogramBase::Sample>(
688 TimeDelta::FromSeconds(10).InMicroseconds()),
689 50);
690 } else {
691 UMA_HISTOGRAM_CUSTOM_COUNTS(
692 "GPU.ProgramCache.BinaryCacheHitTime",
693 static_cast<base::HistogramBase::Sample>(
694 (TimeTicks::Now() - before_time).InMicroseconds()),
696 static_cast<base::HistogramBase::Sample>(
697 TimeDelta::FromSeconds(1).InMicroseconds()),
698 50);
700 } else {
701 UpdateLogInfo();
703 return success == GL_TRUE;
706 void Program::Validate() {
707 if (!IsValid()) {
708 set_log_info("program not linked");
709 return;
711 glValidateProgram(service_id());
712 UpdateLogInfo();
715 GLint Program::GetUniformFakeLocation(
716 const std::string& name) const {
717 bool getting_array_location = false;
718 size_t open_pos = std::string::npos;
719 int index = 0;
720 if (!GLES2Util::ParseUniformName(
721 name, &open_pos, &index, &getting_array_location)) {
722 return -1;
724 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
725 const UniformInfo& info = uniform_infos_[ii];
726 if (!info.IsValid()) {
727 continue;
729 if (info.name == name ||
730 (info.is_array &&
731 info.name.compare(0, info.name.size() - 3, name) == 0)) {
732 return info.fake_location_base;
733 } else if (getting_array_location && info.is_array) {
734 // Look for an array specification.
735 size_t open_pos_2 = info.name.find_last_of('[');
736 if (open_pos_2 == open_pos &&
737 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
738 if (index >= 0 && index < info.size) {
739 DCHECK_GT(static_cast<int>(info.element_locations.size()), index);
740 if (info.element_locations[index] == -1)
741 return -1;
742 return ProgramManager::MakeFakeLocation(
743 info.fake_location_base, index);
748 return -1;
751 GLint Program::GetAttribLocation(
752 const std::string& original_name) const {
753 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
754 const VertexAttrib& info = attrib_infos_[ii];
755 if (info.name == original_name) {
756 return info.location;
759 return -1;
762 const Program::UniformInfo*
763 Program::GetUniformInfoByFakeLocation(
764 GLint fake_location, GLint* real_location, GLint* array_index) const {
765 DCHECK(real_location);
766 DCHECK(array_index);
767 if (fake_location < 0) {
768 return NULL;
771 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
772 if (uniform_index >= 0 &&
773 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
774 const UniformInfo& uniform_info = uniform_infos_[uniform_index];
775 if (!uniform_info.IsValid()) {
776 return NULL;
778 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
779 if (element_index < uniform_info.size) {
780 *real_location = uniform_info.element_locations[element_index];
781 *array_index = element_index;
782 return &uniform_info;
785 return NULL;
788 const std::string* Program::GetAttribMappedName(
789 const std::string& original_name) const {
790 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
791 Shader* shader = attached_shaders_[ii].get();
792 if (shader) {
793 const std::string* mapped_name =
794 shader->GetAttribMappedName(original_name);
795 if (mapped_name)
796 return mapped_name;
799 return NULL;
802 const std::string* Program::GetOriginalNameFromHashedName(
803 const std::string& hashed_name) const {
804 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
805 Shader* shader = attached_shaders_[ii].get();
806 if (shader) {
807 const std::string* original_name =
808 shader->GetOriginalNameFromHashedName(hashed_name);
809 if (original_name)
810 return original_name;
813 return NULL;
816 bool Program::SetUniformLocationBinding(
817 const std::string& name, GLint location) {
818 std::string short_name;
819 int element_index = 0;
820 if (!GetUniformNameSansElement(name, &element_index, &short_name) ||
821 element_index != 0) {
822 return false;
825 bind_uniform_location_map_[short_name] = location;
826 return true;
829 // Note: This is only valid to call right after a program has been linked
830 // successfully.
831 void Program::GetCorrectedUniformData(
832 const std::string& name,
833 std::string* corrected_name, std::string* original_name,
834 GLsizei* size, GLenum* type) const {
835 DCHECK(corrected_name && original_name && size && type);
836 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
837 Shader* shader = attached_shaders_[ii].get();
838 if (!shader)
839 continue;
840 const sh::ShaderVariable* info = NULL;
841 const sh::Uniform* uniform = shader->GetUniformInfo(name);
842 bool found = false;
843 if (uniform)
844 found = uniform->findInfoByMappedName(name, &info, original_name);
845 if (found) {
846 const std::string kArraySpec("[0]");
847 if (info->arraySize > 0 &&
848 !base::EndsWith(name, kArraySpec, base::CompareCase::SENSITIVE)) {
849 *corrected_name = name + kArraySpec;
850 *original_name += kArraySpec;
851 } else {
852 *corrected_name = name;
854 *type = info->type;
855 *size = std::max(1u, info->arraySize);
856 return;
859 // TODO(zmo): this path should never be reached unless there is a serious
860 // bug in the driver or in ANGLE translator.
861 *corrected_name = name;
862 *original_name = name;
865 void Program::GetVertexAttribData(
866 const std::string& name, std::string* original_name, GLenum* type) const {
867 DCHECK(original_name);
868 DCHECK(type);
869 Shader* shader = attached_shaders_[ShaderTypeToIndex(GL_VERTEX_SHADER)].get();
870 if (shader) {
871 // Vertex attributes can not be arrays or structs (GLSL ES 3.00.4, section
872 // 4.3.4, "Input Variables"), so the top level sh::Attribute returns the
873 // information we need.
874 const sh::Attribute* info = shader->GetAttribInfo(name);
875 if (info) {
876 *original_name = info->name;
877 *type = info->type;
878 return;
881 // TODO(zmo): this path should never be reached unless there is a serious
882 // bug in the driver or in ANGLE translator.
883 *original_name = name;
886 bool Program::AddUniformInfo(
887 GLsizei size, GLenum type, GLint location, GLint fake_base_location,
888 const std::string& name, const std::string& original_name,
889 size_t* next_available_index) {
890 DCHECK(next_available_index);
891 const char* kArraySpec = "[0]";
892 size_t uniform_index =
893 fake_base_location >= 0 ? fake_base_location : *next_available_index;
894 if (uniform_infos_.size() < uniform_index + 1) {
895 uniform_infos_.resize(uniform_index + 1);
898 // return if this location is already in use.
899 if (uniform_infos_[uniform_index].IsValid()) {
900 DCHECK_GE(fake_base_location, 0);
901 return false;
904 uniform_infos_[uniform_index] = UniformInfo(
905 size, type, uniform_index, original_name);
906 ++num_uniforms_;
908 UniformInfo& info = uniform_infos_[uniform_index];
909 info.element_locations.resize(size);
910 info.element_locations[0] = location;
911 DCHECK_GE(size, 0);
912 size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
913 info.texture_units.clear();
914 info.texture_units.resize(num_texture_units, 0);
916 if (size > 1) {
917 // Go through the array element locations looking for a match.
918 // We can skip the first element because it's the same as the
919 // the location without the array operators.
920 size_t array_pos = name.rfind(kArraySpec);
921 std::string base_name = name;
922 if (name.size() > 3) {
923 if (array_pos != name.size() - 3) {
924 info.name = name + kArraySpec;
925 } else {
926 base_name = name.substr(0, name.size() - 3);
929 for (GLsizei ii = 1; ii < info.size; ++ii) {
930 std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
931 info.element_locations[ii] =
932 glGetUniformLocation(service_id_, element_name.c_str());
936 info.is_array =
937 (size > 1 ||
938 (info.name.size() > 3 &&
939 info.name.rfind(kArraySpec) == info.name.size() - 3));
941 if (info.IsSampler()) {
942 sampler_indices_.push_back(info.fake_location_base);
944 max_uniform_name_length_ =
945 std::max(max_uniform_name_length_,
946 static_cast<GLsizei>(info.name.size()));
948 while (*next_available_index < uniform_infos_.size() &&
949 uniform_infos_[*next_available_index].IsValid()) {
950 *next_available_index = *next_available_index + 1;
953 return true;
956 const Program::UniformInfo*
957 Program::GetUniformInfo(
958 GLint index) const {
959 if (static_cast<size_t>(index) >= uniform_infos_.size()) {
960 return NULL;
963 const UniformInfo& info = uniform_infos_[index];
964 return info.IsValid() ? &info : NULL;
967 bool Program::SetSamplers(
968 GLint num_texture_units, GLint fake_location,
969 GLsizei count, const GLint* value) {
970 if (fake_location < 0) {
971 return true;
973 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
974 if (uniform_index >= 0 &&
975 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
976 UniformInfo& info = uniform_infos_[uniform_index];
977 if (!info.IsValid()) {
978 return false;
980 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
981 if (element_index < info.size) {
982 count = std::min(info.size - element_index, count);
983 if (info.IsSampler() && count > 0) {
984 for (GLsizei ii = 0; ii < count; ++ii) {
985 if (value[ii] < 0 || value[ii] >= num_texture_units) {
986 return false;
989 std::copy(value, value + count,
990 info.texture_units.begin() + element_index);
991 return true;
995 return true;
998 void Program::GetProgramiv(GLenum pname, GLint* params) {
999 switch (pname) {
1000 case GL_ACTIVE_ATTRIBUTES:
1001 *params = attrib_infos_.size();
1002 break;
1003 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
1004 // Notice +1 to accomodate NULL terminator.
1005 *params = max_attrib_name_length_ + 1;
1006 break;
1007 case GL_ACTIVE_UNIFORMS:
1008 *params = num_uniforms_;
1009 break;
1010 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
1011 // Notice +1 to accomodate NULL terminator.
1012 *params = max_uniform_name_length_ + 1;
1013 break;
1014 case GL_LINK_STATUS:
1015 *params = link_status_;
1016 break;
1017 case GL_INFO_LOG_LENGTH:
1018 // Notice +1 to accomodate NULL terminator.
1019 *params = log_info_.get() ? (log_info_->size() + 1) : 0;
1020 break;
1021 case GL_DELETE_STATUS:
1022 *params = deleted_;
1023 break;
1024 case GL_VALIDATE_STATUS:
1025 if (!IsValid()) {
1026 *params = GL_FALSE;
1027 } else {
1028 glGetProgramiv(service_id_, pname, params);
1030 break;
1031 default:
1032 glGetProgramiv(service_id_, pname, params);
1033 break;
1037 bool Program::AttachShader(
1038 ShaderManager* shader_manager,
1039 Shader* shader) {
1040 DCHECK(shader_manager);
1041 DCHECK(shader);
1042 int index = ShaderTypeToIndex(shader->shader_type());
1043 if (attached_shaders_[index].get() != NULL) {
1044 return false;
1046 attached_shaders_[index] = scoped_refptr<Shader>(shader);
1047 shader_manager->UseShader(shader);
1048 return true;
1051 bool Program::DetachShader(
1052 ShaderManager* shader_manager,
1053 Shader* shader) {
1054 DCHECK(shader_manager);
1055 DCHECK(shader);
1056 if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() !=
1057 shader) {
1058 return false;
1060 attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL;
1061 shader_manager->UnuseShader(shader);
1062 return true;
1065 void Program::DetachShaders(ShaderManager* shader_manager) {
1066 DCHECK(shader_manager);
1067 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1068 if (attached_shaders_[ii].get()) {
1069 DetachShader(shader_manager, attached_shaders_[ii].get());
1074 void Program::CompileAttachedShaders() {
1075 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1076 Shader* shader = attached_shaders_[ii].get();
1077 if (shader) {
1078 shader->DoCompile();
1083 bool Program::AttachedShadersExist() const {
1084 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1085 if (!attached_shaders_[ii].get())
1086 return false;
1088 return true;
1091 bool Program::CanLink() const {
1092 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1093 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid()) {
1094 return false;
1097 return true;
1100 bool Program::DetectShaderVersionMismatch() const {
1101 int version = Shader::kUndefinedShaderVersion;
1102 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1103 Shader* shader = attached_shaders_[ii].get();
1104 if (shader) {
1105 if (version != Shader::kUndefinedShaderVersion &&
1106 shader->shader_version() != version) {
1107 return true;
1109 version = shader->shader_version();
1110 DCHECK(version != Shader::kUndefinedShaderVersion);
1113 return false;
1116 bool Program::DetectAttribLocationBindingConflicts() const {
1117 std::set<GLint> location_binding_used;
1118 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
1119 it != bind_attrib_location_map_.end(); ++it) {
1120 // Find out if an attribute is statically used in this program's shaders.
1121 const sh::Attribute* attrib = NULL;
1122 const std::string* mapped_name = GetAttribMappedName(it->first);
1123 if (!mapped_name)
1124 continue;
1125 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1126 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid())
1127 continue;
1128 attrib = attached_shaders_[ii]->GetAttribInfo(*mapped_name);
1129 if (attrib) {
1130 if (attrib->staticUse)
1131 break;
1132 else
1133 attrib = NULL;
1136 if (attrib) {
1137 size_t num_of_locations = 1;
1138 switch (attrib->type) {
1139 case GL_FLOAT_MAT2:
1140 num_of_locations = 2;
1141 break;
1142 case GL_FLOAT_MAT3:
1143 num_of_locations = 3;
1144 break;
1145 case GL_FLOAT_MAT4:
1146 num_of_locations = 4;
1147 break;
1148 default:
1149 break;
1151 for (size_t ii = 0; ii < num_of_locations; ++ii) {
1152 GLint loc = it->second + ii;
1153 std::pair<std::set<GLint>::iterator, bool> result =
1154 location_binding_used.insert(loc);
1155 if (!result.second)
1156 return true;
1160 return false;
1163 bool Program::DetectUniformsMismatch(std::string* conflicting_name) const {
1164 typedef std::map<std::string, const sh::Uniform*> UniformPointerMap;
1165 UniformPointerMap uniform_pointer_map;
1166 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1167 const UniformMap& shader_uniforms = attached_shaders_[ii]->uniform_map();
1168 for (UniformMap::const_iterator iter = shader_uniforms.begin();
1169 iter != shader_uniforms.end(); ++iter) {
1170 const std::string& name = iter->first;
1171 UniformPointerMap::iterator hit = uniform_pointer_map.find(name);
1172 if (hit == uniform_pointer_map.end()) {
1173 uniform_pointer_map[name] = &(iter->second);
1174 } else {
1175 // If a uniform is in the map, i.e., it has already been declared by
1176 // another shader, then the type, precision, etc. must match.
1177 if (hit->second->isSameUniformAtLinkTime(iter->second))
1178 continue;
1179 *conflicting_name = name;
1180 return true;
1184 return false;
1187 bool Program::DetectVaryingsMismatch(std::string* conflicting_name) const {
1188 DCHECK(attached_shaders_[0].get() &&
1189 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1190 attached_shaders_[1].get() &&
1191 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1192 const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
1193 const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
1195 int shader_version = attached_shaders_[0]->shader_version();
1197 for (VaryingMap::const_iterator iter = fragment_varyings->begin();
1198 iter != fragment_varyings->end(); ++iter) {
1199 const std::string& name = iter->first;
1200 if (IsBuiltInFragmentVarying(name))
1201 continue;
1203 VaryingMap::const_iterator hit = vertex_varyings->find(name);
1204 if (hit == vertex_varyings->end()) {
1205 if (iter->second.staticUse) {
1206 *conflicting_name = name;
1207 return true;
1209 continue;
1212 if (!hit->second.isSameVaryingAtLinkTime(iter->second, shader_version)) {
1213 *conflicting_name = name;
1214 return true;
1218 return false;
1221 bool Program::DetectBuiltInInvariantConflicts() const {
1222 DCHECK(attached_shaders_[0].get() &&
1223 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1224 attached_shaders_[1].get() &&
1225 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1226 const VaryingMap& vertex_varyings = attached_shaders_[0]->varying_map();
1227 const VaryingMap& fragment_varyings = attached_shaders_[1]->varying_map();
1229 bool gl_position_invariant = IsBuiltInInvariant(
1230 vertex_varyings, "gl_Position");
1231 bool gl_point_size_invariant = IsBuiltInInvariant(
1232 vertex_varyings, "gl_PointSize");
1234 bool gl_frag_coord_invariant = IsBuiltInInvariant(
1235 fragment_varyings, "gl_FragCoord");
1236 bool gl_point_coord_invariant = IsBuiltInInvariant(
1237 fragment_varyings, "gl_PointCoord");
1239 return ((gl_frag_coord_invariant && !gl_position_invariant) ||
1240 (gl_point_coord_invariant && !gl_point_size_invariant));
1243 bool Program::DetectGlobalNameConflicts(std::string* conflicting_name) const {
1244 DCHECK(attached_shaders_[0].get() &&
1245 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1246 attached_shaders_[1].get() &&
1247 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1248 const UniformMap* uniforms[2];
1249 uniforms[0] = &(attached_shaders_[0]->uniform_map());
1250 uniforms[1] = &(attached_shaders_[1]->uniform_map());
1251 const AttributeMap* attribs =
1252 &(attached_shaders_[0]->attrib_map());
1254 for (AttributeMap::const_iterator iter = attribs->begin();
1255 iter != attribs->end(); ++iter) {
1256 for (int ii = 0; ii < 2; ++ii) {
1257 if (uniforms[ii]->find(iter->first) != uniforms[ii]->end()) {
1258 *conflicting_name = iter->first;
1259 return true;
1263 return false;
1266 bool Program::CheckVaryingsPacking(
1267 Program::VaryingsPackingOption option) const {
1268 DCHECK(attached_shaders_[0].get() &&
1269 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1270 attached_shaders_[1].get() &&
1271 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1272 const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
1273 const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
1275 std::map<std::string, ShVariableInfo> combined_map;
1277 for (VaryingMap::const_iterator iter = fragment_varyings->begin();
1278 iter != fragment_varyings->end(); ++iter) {
1279 if (!iter->second.staticUse && option == kCountOnlyStaticallyUsed)
1280 continue;
1281 if (!IsBuiltInFragmentVarying(iter->first)) {
1282 VaryingMap::const_iterator vertex_iter =
1283 vertex_varyings->find(iter->first);
1284 if (vertex_iter == vertex_varyings->end() ||
1285 (!vertex_iter->second.staticUse &&
1286 option == kCountOnlyStaticallyUsed))
1287 continue;
1290 ShVariableInfo var;
1291 var.type = static_cast<sh::GLenum>(iter->second.type);
1292 var.size = std::max(1u, iter->second.arraySize);
1293 combined_map[iter->first] = var;
1296 if (combined_map.size() == 0)
1297 return true;
1298 scoped_ptr<ShVariableInfo[]> variables(
1299 new ShVariableInfo[combined_map.size()]);
1300 size_t index = 0;
1301 for (std::map<std::string, ShVariableInfo>::const_iterator iter =
1302 combined_map.begin();
1303 iter != combined_map.end(); ++iter) {
1304 variables[index].type = iter->second.type;
1305 variables[index].size = iter->second.size;
1306 ++index;
1308 return ShCheckVariablesWithinPackingLimits(
1309 static_cast<int>(manager_->max_varying_vectors()),
1310 variables.get(),
1311 combined_map.size());
1314 void Program::GetProgramInfo(
1315 ProgramManager* manager, CommonDecoder::Bucket* bucket) const {
1316 // NOTE: It seems to me the math in here does not need check for overflow
1317 // because the data being calucated from has various small limits. The max
1318 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1319 // of an identifier is 256 characters.
1320 uint32 num_locations = 0;
1321 uint32 total_string_size = 0;
1323 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1324 const VertexAttrib& info = attrib_infos_[ii];
1325 num_locations += 1;
1326 total_string_size += info.name.size();
1329 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1330 const UniformInfo& info = uniform_infos_[ii];
1331 if (info.IsValid()) {
1332 num_locations += info.element_locations.size();
1333 total_string_size += info.name.size();
1337 uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
1338 uint32 input_size = num_inputs * sizeof(ProgramInput);
1339 uint32 location_size = num_locations * sizeof(int32);
1340 uint32 size = sizeof(ProgramInfoHeader) +
1341 input_size + location_size + total_string_size;
1343 bucket->SetSize(size);
1344 ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
1345 ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
1346 sizeof(ProgramInfoHeader), input_size);
1347 int32* locations = bucket->GetDataAs<int32*>(
1348 sizeof(ProgramInfoHeader) + input_size, location_size);
1349 char* strings = bucket->GetDataAs<char*>(
1350 sizeof(ProgramInfoHeader) + input_size + location_size,
1351 total_string_size);
1352 DCHECK(header);
1353 DCHECK(inputs);
1354 DCHECK(locations);
1355 DCHECK(strings);
1357 header->link_status = link_status_;
1358 header->num_attribs = attrib_infos_.size();
1359 header->num_uniforms = num_uniforms_;
1361 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1362 const VertexAttrib& info = attrib_infos_[ii];
1363 inputs->size = info.size;
1364 inputs->type = info.type;
1365 inputs->location_offset = ComputeOffset(header, locations);
1366 inputs->name_offset = ComputeOffset(header, strings);
1367 inputs->name_length = info.name.size();
1368 *locations++ = info.location;
1369 memcpy(strings, info.name.c_str(), info.name.size());
1370 strings += info.name.size();
1371 ++inputs;
1374 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1375 const UniformInfo& info = uniform_infos_[ii];
1376 if (info.IsValid()) {
1377 inputs->size = info.size;
1378 inputs->type = info.type;
1379 inputs->location_offset = ComputeOffset(header, locations);
1380 inputs->name_offset = ComputeOffset(header, strings);
1381 inputs->name_length = info.name.size();
1382 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
1383 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
1384 if (info.element_locations[jj] == -1)
1385 *locations++ = -1;
1386 else
1387 *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
1389 memcpy(strings, info.name.c_str(), info.name.size());
1390 strings += info.name.size();
1391 ++inputs;
1395 DCHECK_EQ(ComputeOffset(header, strings), size);
1398 bool Program::GetUniformBlocks(CommonDecoder::Bucket* bucket) const {
1399 // The data is packed into the bucket in the following order
1400 // 1) header
1401 // 2) N entries of block data (except for name and indices)
1402 // 3) name1, indices1, name2, indices2, ..., nameN, indicesN
1404 // We query all the data directly through GL calls, assuming they are
1405 // cheap through MANGLE.
1407 DCHECK(bucket);
1408 GLuint program = service_id();
1410 uint32_t header_size = sizeof(UniformBlocksHeader);
1411 bucket->SetSize(header_size); // In case we fail.
1413 uint32_t num_uniform_blocks = 0;
1414 GLint param = GL_FALSE;
1415 // We assume program is a valid program service id.
1416 glGetProgramiv(program, GL_LINK_STATUS, &param);
1417 if (param == GL_TRUE) {
1418 param = 0;
1419 glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &param);
1420 num_uniform_blocks = static_cast<uint32_t>(param);
1422 if (num_uniform_blocks == 0) {
1423 // Although spec allows an implementation to return uniform block info
1424 // even if a link fails, for consistency, we disallow that.
1425 return true;
1428 std::vector<UniformBlockInfo> blocks(num_uniform_blocks);
1429 base::CheckedNumeric<uint32_t> size = sizeof(UniformBlockInfo);
1430 size *= num_uniform_blocks;
1431 uint32_t entry_size = size.ValueOrDefault(0);
1432 size += header_size;
1433 std::vector<std::string> names(num_uniform_blocks);
1434 GLint max_name_length = 0;
1435 glGetProgramiv(
1436 program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_name_length);
1437 std::vector<GLchar> buffer(max_name_length);
1438 GLsizei length;
1439 for (uint32_t ii = 0; ii < num_uniform_blocks; ++ii) {
1440 param = 0;
1441 glGetActiveUniformBlockiv(program, ii, GL_UNIFORM_BLOCK_BINDING, &param);
1442 blocks[ii].binding = static_cast<uint32_t>(param);
1444 param = 0;
1445 glGetActiveUniformBlockiv(program, ii, GL_UNIFORM_BLOCK_DATA_SIZE, &param);
1446 blocks[ii].data_size = static_cast<uint32_t>(param);
1448 blocks[ii].name_offset = size.ValueOrDefault(0);
1449 param = 0;
1450 glGetActiveUniformBlockiv(
1451 program, ii, GL_UNIFORM_BLOCK_NAME_LENGTH, &param);
1452 DCHECK_GE(max_name_length, param);
1453 memset(&buffer[0], 0, param);
1454 length = 0;
1455 glGetActiveUniformBlockName(
1456 program, ii, static_cast<GLsizei>(param), &length, &buffer[0]);
1457 DCHECK_EQ(param, length + 1);
1458 names[ii] = std::string(&buffer[0], length);
1459 // TODO(zmo): optimize the name mapping lookup.
1460 const std::string* original_name = GetOriginalNameFromHashedName(names[ii]);
1461 if (original_name)
1462 names[ii] = *original_name;
1463 blocks[ii].name_length = names[ii].size() + 1;
1464 size += blocks[ii].name_length;
1466 param = 0;
1467 glGetActiveUniformBlockiv(
1468 program, ii, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &param);
1469 blocks[ii].active_uniforms = static_cast<uint32_t>(param);
1470 blocks[ii].active_uniform_offset = size.ValueOrDefault(0);
1471 base::CheckedNumeric<uint32_t> indices_size = blocks[ii].active_uniforms;
1472 indices_size *= sizeof(uint32_t);
1473 if (!indices_size.IsValid())
1474 return false;
1475 size += indices_size.ValueOrDefault(0);
1477 param = 0;
1478 glGetActiveUniformBlockiv(
1479 program, ii, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &param);
1480 blocks[ii].referenced_by_vertex_shader = static_cast<uint32_t>(param);
1482 param = 0;
1483 glGetActiveUniformBlockiv(
1484 program, ii, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &param);
1485 blocks[ii].referenced_by_fragment_shader = static_cast<uint32_t>(param);
1487 if (!size.IsValid())
1488 return false;
1489 uint32_t total_size = size.ValueOrDefault(0);
1490 DCHECK_LE(header_size + entry_size, total_size);
1491 uint32_t data_size = total_size - header_size - entry_size;
1493 bucket->SetSize(total_size);
1494 UniformBlocksHeader* header =
1495 bucket->GetDataAs<UniformBlocksHeader*>(0, header_size);
1496 UniformBlockInfo* entries = bucket->GetDataAs<UniformBlockInfo*>(
1497 header_size, entry_size);
1498 char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size);
1499 DCHECK(header);
1500 DCHECK(entries);
1501 DCHECK(data);
1503 // Copy over data for the header and entries.
1504 header->num_uniform_blocks = num_uniform_blocks;
1505 memcpy(entries, &blocks[0], entry_size);
1507 std::vector<GLint> params;
1508 for (uint32_t ii = 0; ii < num_uniform_blocks; ++ii) {
1509 // Get active uniform name.
1510 memcpy(data, names[ii].c_str(), names[ii].length() + 1);
1511 data += names[ii].length() + 1;
1513 // Get active uniform indices.
1514 if (params.size() < blocks[ii].active_uniforms)
1515 params.resize(blocks[ii].active_uniforms);
1516 uint32_t num_bytes = blocks[ii].active_uniforms * sizeof(GLint);
1517 memset(&params[0], 0, num_bytes);
1518 glGetActiveUniformBlockiv(
1519 program, ii, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, &params[0]);
1520 uint32_t* indices = reinterpret_cast<uint32_t*>(data);
1521 for (uint32_t uu = 0; uu < blocks[ii].active_uniforms; ++uu) {
1522 indices[uu] = static_cast<uint32_t>(params[uu]);
1524 data += num_bytes;
1526 DCHECK_EQ(ComputeOffset(header, data), total_size);
1527 return true;
1530 bool Program::GetTransformFeedbackVaryings(
1531 CommonDecoder::Bucket* bucket) const {
1532 // The data is packed into the bucket in the following order
1533 // 1) header
1534 // 2) N entries of varying data (except for name)
1535 // 3) name1, name2, ..., nameN
1537 // We query all the data directly through GL calls, assuming they are
1538 // cheap through MANGLE.
1540 DCHECK(bucket);
1541 GLuint program = service_id();
1543 uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader);
1544 bucket->SetSize(header_size); // In case we fail.
1546 uint32_t num_transform_feedback_varyings = 0;
1547 GLint param = GL_FALSE;
1548 // We assume program is a valid program service id.
1549 glGetProgramiv(program, GL_LINK_STATUS, &param);
1550 if (param == GL_TRUE) {
1551 param = 0;
1552 glGetProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &param);
1553 num_transform_feedback_varyings = static_cast<uint32_t>(param);
1555 if (num_transform_feedback_varyings == 0) {
1556 return true;
1559 std::vector<TransformFeedbackVaryingInfo> varyings(
1560 num_transform_feedback_varyings);
1561 base::CheckedNumeric<uint32_t> size = sizeof(TransformFeedbackVaryingInfo);
1562 size *= num_transform_feedback_varyings;
1563 uint32_t entry_size = size.ValueOrDefault(0);
1564 size += header_size;
1565 std::vector<std::string> names(num_transform_feedback_varyings);
1566 GLint max_name_length = 0;
1567 glGetProgramiv(
1568 program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &max_name_length);
1569 if (max_name_length < 1)
1570 max_name_length = 1;
1571 std::vector<char> buffer(max_name_length);
1572 for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) {
1573 GLsizei var_size = 0;
1574 GLsizei var_name_length = 0;
1575 GLenum var_type = 0;
1576 glGetTransformFeedbackVarying(
1577 program, ii, max_name_length,
1578 &var_name_length, &var_size, &var_type, &buffer[0]);
1579 varyings[ii].size = static_cast<uint32_t>(var_size);
1580 varyings[ii].type = static_cast<uint32_t>(var_type);
1581 varyings[ii].name_offset = static_cast<uint32_t>(size.ValueOrDefault(0));
1582 DCHECK_GT(max_name_length, var_name_length);
1583 names[ii] = std::string(&buffer[0], var_name_length);
1584 // TODO(zmo): optimize the name mapping lookup.
1585 const std::string* original_name = GetOriginalNameFromHashedName(names[ii]);
1586 if (original_name)
1587 names[ii] = *original_name;
1588 varyings[ii].name_length = names[ii].size() + 1;
1589 size += names[ii].size();
1590 size += 1;
1592 if (!size.IsValid())
1593 return false;
1594 uint32_t total_size = size.ValueOrDefault(0);
1595 DCHECK_LE(header_size + entry_size, total_size);
1596 uint32_t data_size = total_size - header_size - entry_size;
1598 bucket->SetSize(total_size);
1599 TransformFeedbackVaryingsHeader* header =
1600 bucket->GetDataAs<TransformFeedbackVaryingsHeader*>(0, header_size);
1601 TransformFeedbackVaryingInfo* entries =
1602 bucket->GetDataAs<TransformFeedbackVaryingInfo*>(header_size, entry_size);
1603 char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size);
1604 DCHECK(header);
1605 DCHECK(entries);
1606 DCHECK(data);
1608 // Copy over data for the header and entries.
1609 header->num_transform_feedback_varyings = num_transform_feedback_varyings;
1610 memcpy(entries, &varyings[0], entry_size);
1612 for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) {
1613 memcpy(data, names[ii].c_str(), names[ii].length() + 1);
1614 data += names[ii].length() + 1;
1616 DCHECK_EQ(ComputeOffset(header, data), total_size);
1617 return true;
1620 bool Program::GetUniformsES3(CommonDecoder::Bucket* bucket) const {
1621 // The data is packed into the bucket in the following order
1622 // 1) header
1623 // 2) N entries of UniformES3Info
1625 // We query all the data directly through GL calls, assuming they are
1626 // cheap through MANGLE.
1628 DCHECK(bucket);
1629 GLuint program = service_id();
1631 uint32_t header_size = sizeof(UniformsES3Header);
1632 bucket->SetSize(header_size); // In case we fail.
1634 GLsizei count = 0;
1635 GLint param = GL_FALSE;
1636 // We assume program is a valid program service id.
1637 glGetProgramiv(program, GL_LINK_STATUS, &param);
1638 if (param == GL_TRUE) {
1639 param = 0;
1640 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count);
1642 if (count == 0) {
1643 return true;
1646 base::CheckedNumeric<uint32_t> size = sizeof(UniformES3Info);
1647 size *= count;
1648 uint32_t entry_size = size.ValueOrDefault(0);
1649 size += header_size;
1650 if (!size.IsValid())
1651 return false;
1652 uint32_t total_size = size.ValueOrDefault(0);
1653 bucket->SetSize(total_size);
1654 UniformsES3Header* header =
1655 bucket->GetDataAs<UniformsES3Header*>(0, header_size);
1656 DCHECK(header);
1657 header->num_uniforms = static_cast<uint32_t>(count);
1659 // Instead of GetDataAs<UniformES3Info*>, we do GetDataAs<int32_t>. This is
1660 // because struct UniformES3Info is defined as five int32_t.
1661 // By doing this, we can fill the structs through loops.
1662 int32_t* entries =
1663 bucket->GetDataAs<int32_t*>(header_size, entry_size);
1664 DCHECK(entries);
1665 const size_t kStride = sizeof(UniformES3Info) / sizeof(int32_t);
1667 const GLenum kPname[] = {
1668 GL_UNIFORM_BLOCK_INDEX,
1669 GL_UNIFORM_OFFSET,
1670 GL_UNIFORM_ARRAY_STRIDE,
1671 GL_UNIFORM_MATRIX_STRIDE,
1672 GL_UNIFORM_IS_ROW_MAJOR,
1674 const GLint kDefaultValue[] = { -1, -1, -1, -1, 0 };
1675 const size_t kNumPnames = arraysize(kPname);
1676 std::vector<GLuint> indices(count);
1677 for (GLsizei ii = 0; ii < count; ++ii) {
1678 indices[ii] = ii;
1680 std::vector<GLint> params(count);
1681 for (size_t pname_index = 0; pname_index < kNumPnames; ++pname_index) {
1682 for (GLsizei ii = 0; ii < count; ++ii) {
1683 params[ii] = kDefaultValue[pname_index];
1685 glGetActiveUniformsiv(
1686 program, count, &indices[0], kPname[pname_index], &params[0]);
1687 for (GLsizei ii = 0; ii < count; ++ii) {
1688 entries[kStride * ii + pname_index] = params[ii];
1691 return true;
1694 void Program::TransformFeedbackVaryings(GLsizei count,
1695 const char* const* varyings,
1696 GLenum buffer_mode) {
1697 transform_feedback_varyings_.clear();
1698 for (GLsizei i = 0; i < count; ++i) {
1699 transform_feedback_varyings_.push_back(std::string(varyings[i]));
1701 transform_feedback_buffer_mode_ = buffer_mode;
1704 Program::~Program() {
1705 if (manager_) {
1706 if (manager_->have_context_) {
1707 glDeleteProgram(service_id());
1709 manager_->StopTracking(this);
1710 manager_ = NULL;
1715 ProgramManager::ProgramManager(ProgramCache* program_cache,
1716 uint32 max_varying_vectors)
1717 : program_count_(0),
1718 have_context_(true),
1719 program_cache_(program_cache),
1720 max_varying_vectors_(max_varying_vectors) { }
1722 ProgramManager::~ProgramManager() {
1723 DCHECK(programs_.empty());
1726 void ProgramManager::Destroy(bool have_context) {
1727 have_context_ = have_context;
1728 programs_.clear();
1731 void ProgramManager::StartTracking(Program* /* program */) {
1732 ++program_count_;
1735 void ProgramManager::StopTracking(Program* /* program */) {
1736 --program_count_;
1739 Program* ProgramManager::CreateProgram(
1740 GLuint client_id, GLuint service_id) {
1741 std::pair<ProgramMap::iterator, bool> result =
1742 programs_.insert(
1743 std::make_pair(client_id,
1744 scoped_refptr<Program>(
1745 new Program(this, service_id))));
1746 DCHECK(result.second);
1747 return result.first->second.get();
1750 Program* ProgramManager::GetProgram(GLuint client_id) {
1751 ProgramMap::iterator it = programs_.find(client_id);
1752 return it != programs_.end() ? it->second.get() : NULL;
1755 bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
1756 // This doesn't need to be fast. It's only used during slow queries.
1757 for (ProgramMap::const_iterator it = programs_.begin();
1758 it != programs_.end(); ++it) {
1759 if (it->second->service_id() == service_id) {
1760 *client_id = it->first;
1761 return true;
1764 return false;
1767 ProgramCache* ProgramManager::program_cache() const {
1768 return program_cache_;
1771 bool ProgramManager::IsOwned(Program* program) {
1772 for (ProgramMap::iterator it = programs_.begin();
1773 it != programs_.end(); ++it) {
1774 if (it->second.get() == program) {
1775 return true;
1778 return false;
1781 void ProgramManager::RemoveProgramInfoIfUnused(
1782 ShaderManager* shader_manager, Program* program) {
1783 DCHECK(shader_manager);
1784 DCHECK(program);
1785 DCHECK(IsOwned(program));
1786 if (program->IsDeleted() && !program->InUse()) {
1787 program->DetachShaders(shader_manager);
1788 for (ProgramMap::iterator it = programs_.begin();
1789 it != programs_.end(); ++it) {
1790 if (it->second.get() == program) {
1791 programs_.erase(it);
1792 return;
1795 NOTREACHED();
1799 void ProgramManager::MarkAsDeleted(
1800 ShaderManager* shader_manager,
1801 Program* program) {
1802 DCHECK(shader_manager);
1803 DCHECK(program);
1804 DCHECK(IsOwned(program));
1805 program->MarkAsDeleted();
1806 RemoveProgramInfoIfUnused(shader_manager, program);
1809 void ProgramManager::UseProgram(Program* program) {
1810 DCHECK(program);
1811 DCHECK(IsOwned(program));
1812 program->IncUseCount();
1815 void ProgramManager::UnuseProgram(
1816 ShaderManager* shader_manager,
1817 Program* program) {
1818 DCHECK(shader_manager);
1819 DCHECK(program);
1820 DCHECK(IsOwned(program));
1821 program->DecUseCount();
1822 RemoveProgramInfoIfUnused(shader_manager, program);
1825 void ProgramManager::ClearUniforms(Program* program) {
1826 DCHECK(program);
1827 program->ClearUniforms(&zero_);
1830 int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
1831 return index + element * 0x10000;
1834 } // namespace gles2
1835 } // namespace gpu