Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / gpu / command_buffer / service / program_manager.cc
blobaef7e44976e7f70709ec78c1ca5e62e28d7f3b87
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 manager_->StartTracking(this);
218 void Program::Reset() {
219 valid_ = false;
220 link_status_ = false;
221 num_uniforms_ = 0;
222 max_uniform_name_length_ = 0;
223 max_attrib_name_length_ = 0;
224 attrib_infos_.clear();
225 uniform_infos_.clear();
226 sampler_indices_.clear();
227 attrib_location_to_index_map_.clear();
230 std::string Program::ProcessLogInfo(
231 const std::string& log) {
232 std::string output;
233 re2::StringPiece input(log);
234 std::string prior_log;
235 std::string hashed_name;
236 while (RE2::Consume(&input,
237 "(.*?)(webgl_[0123456789abcdefABCDEF]+)",
238 &prior_log,
239 &hashed_name)) {
240 output += prior_log;
242 const std::string* original_name =
243 GetOriginalNameFromHashedName(hashed_name);
244 if (original_name)
245 output += *original_name;
246 else
247 output += hashed_name;
250 return output + input.as_string();
253 void Program::UpdateLogInfo() {
254 GLint max_len = 0;
255 glGetProgramiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
256 if (max_len == 0) {
257 set_log_info(NULL);
258 return;
260 scoped_ptr<char[]> temp(new char[max_len]);
261 GLint len = 0;
262 glGetProgramInfoLog(service_id_, max_len, &len, temp.get());
263 DCHECK(max_len == 0 || len < max_len);
264 DCHECK(len == 0 || temp[len] == '\0');
265 std::string log(temp.get(), len);
266 set_log_info(ProcessLogInfo(log).c_str());
269 void Program::ClearUniforms(
270 std::vector<uint8>* zero_buffer) {
271 DCHECK(zero_buffer);
272 if (uniforms_cleared_) {
273 return;
275 uniforms_cleared_ = true;
276 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
277 const UniformInfo& uniform_info = uniform_infos_[ii];
278 if (!uniform_info.IsValid()) {
279 continue;
281 GLint location = uniform_info.element_locations[0];
282 GLsizei size = uniform_info.size;
283 uint32 unit_size = GLES2Util::GetGLDataTypeSizeForUniforms(
284 uniform_info.type);
285 uint32 size_needed = size * unit_size;
286 if (size_needed > zero_buffer->size()) {
287 zero_buffer->resize(size_needed, 0u);
289 const void* zero = &(*zero_buffer)[0];
290 switch (uniform_info.type) {
291 case GL_FLOAT:
292 glUniform1fv(location, size, reinterpret_cast<const GLfloat*>(zero));
293 break;
294 case GL_FLOAT_VEC2:
295 glUniform2fv(location, size, reinterpret_cast<const GLfloat*>(zero));
296 break;
297 case GL_FLOAT_VEC3:
298 glUniform3fv(location, size, reinterpret_cast<const GLfloat*>(zero));
299 break;
300 case GL_FLOAT_VEC4:
301 glUniform4fv(location, size, reinterpret_cast<const GLfloat*>(zero));
302 break;
303 case GL_INT:
304 case GL_BOOL:
305 case GL_SAMPLER_2D:
306 case GL_SAMPLER_CUBE:
307 case GL_SAMPLER_EXTERNAL_OES:
308 case GL_SAMPLER_3D_OES:
309 case GL_SAMPLER_2D_RECT_ARB:
310 glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero));
311 break;
312 case GL_INT_VEC2:
313 case GL_BOOL_VEC2:
314 glUniform2iv(location, size, reinterpret_cast<const GLint*>(zero));
315 break;
316 case GL_INT_VEC3:
317 case GL_BOOL_VEC3:
318 glUniform3iv(location, size, reinterpret_cast<const GLint*>(zero));
319 break;
320 case GL_INT_VEC4:
321 case GL_BOOL_VEC4:
322 glUniform4iv(location, size, reinterpret_cast<const GLint*>(zero));
323 break;
324 case GL_FLOAT_MAT2:
325 glUniformMatrix2fv(
326 location, size, false, reinterpret_cast<const GLfloat*>(zero));
327 break;
328 case GL_FLOAT_MAT3:
329 glUniformMatrix3fv(
330 location, size, false, reinterpret_cast<const GLfloat*>(zero));
331 break;
332 case GL_FLOAT_MAT4:
333 glUniformMatrix4fv(
334 location, size, false, reinterpret_cast<const GLfloat*>(zero));
335 break;
336 default:
337 NOTREACHED();
338 break;
343 namespace {
345 struct UniformData {
346 UniformData() : size(-1), type(GL_NONE), location(0), added(false) {
348 std::string queried_name;
349 std::string corrected_name;
350 std::string original_name;
351 GLsizei size;
352 GLenum type;
353 GLint location;
354 bool added;
357 struct UniformDataComparer {
358 bool operator()(const UniformData& lhs, const UniformData& rhs) const {
359 return lhs.queried_name < rhs.queried_name;
363 } // anonymous namespace
365 void Program::Update() {
366 Reset();
367 UpdateLogInfo();
368 link_status_ = true;
369 uniforms_cleared_ = false;
370 GLint num_attribs = 0;
371 GLint max_len = 0;
372 GLint max_location = -1;
373 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs);
374 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
375 // TODO(gman): Should we check for error?
376 scoped_ptr<char[]> name_buffer(new char[max_len]);
377 for (GLint ii = 0; ii < num_attribs; ++ii) {
378 GLsizei length = 0;
379 GLsizei size = 0;
380 GLenum type = 0;
381 glGetActiveAttrib(
382 service_id_, ii, max_len, &length, &size, &type, name_buffer.get());
383 DCHECK(max_len == 0 || length < max_len);
384 DCHECK(length == 0 || name_buffer[length] == '\0');
385 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
386 std::string original_name;
387 GetVertexAttribData(name_buffer.get(), &original_name, &type);
388 // TODO(gman): Should we check for error?
389 GLint location = glGetAttribLocation(service_id_, name_buffer.get());
390 if (location > max_location) {
391 max_location = location;
393 attrib_infos_.push_back(
394 VertexAttrib(1, type, original_name, location));
395 max_attrib_name_length_ = std::max(
396 max_attrib_name_length_, static_cast<GLsizei>(original_name.size()));
400 // Create attrib location to index map.
401 attrib_location_to_index_map_.resize(max_location + 1);
402 for (GLint ii = 0; ii <= max_location; ++ii) {
403 attrib_location_to_index_map_[ii] = -1;
405 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
406 const VertexAttrib& info = attrib_infos_[ii];
407 attrib_location_to_index_map_[info.location] = ii;
410 #if !defined(NDEBUG)
411 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
412 switches::kEnableGPUServiceLoggingGPU)) {
413 DVLOG(1) << "----: attribs for service_id: " << service_id();
414 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
415 const VertexAttrib& info = attrib_infos_[ii];
416 DVLOG(1) << ii << ": loc = " << info.location
417 << ", size = " << info.size
418 << ", type = " << GLES2Util::GetStringEnum(info.type)
419 << ", name = " << info.name;
422 #endif
424 max_len = 0;
425 GLint num_uniforms = 0;
426 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
427 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
428 name_buffer.reset(new char[max_len]);
430 // Reads all the names.
431 std::vector<UniformData> uniform_data;
432 for (GLint ii = 0; ii < num_uniforms; ++ii) {
433 GLsizei length = 0;
434 UniformData data;
435 glGetActiveUniform(
436 service_id_, ii, max_len, &length,
437 &data.size, &data.type, name_buffer.get());
438 DCHECK(max_len == 0 || length < max_len);
439 DCHECK(length == 0 || name_buffer[length] == '\0');
440 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
441 data.queried_name = std::string(name_buffer.get());
442 GetCorrectedUniformData(
443 data.queried_name,
444 &data.corrected_name, &data.original_name, &data.size, &data.type);
445 uniform_data.push_back(data);
449 // NOTE: We don't care if 2 uniforms are bound to the same location.
450 // One of them will take preference. The spec allows this, same as
451 // BindAttribLocation.
453 // The reason we don't check is if we were to fail we'd have to
454 // restore the previous program but since we've already linked successfully
455 // at this point the previous program is gone.
457 // Assigns the uniforms with bindings.
458 size_t next_available_index = 0;
459 for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
460 UniformData& data = uniform_data[ii];
461 data.location = glGetUniformLocation(
462 service_id_, data.queried_name.c_str());
463 // remove "[0]"
464 std::string short_name;
465 int element_index = 0;
466 bool good = GetUniformNameSansElement(data.queried_name, &element_index,
467 &short_name);
468 DCHECK(good);
469 LocationMap::const_iterator it = bind_uniform_location_map_.find(
470 short_name);
471 if (it != bind_uniform_location_map_.end()) {
472 data.added = AddUniformInfo(
473 data.size, data.type, data.location, it->second, data.corrected_name,
474 data.original_name, &next_available_index);
478 // Assigns the uniforms that were not bound.
479 for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
480 const UniformData& data = uniform_data[ii];
481 if (!data.added) {
482 AddUniformInfo(
483 data.size, data.type, data.location, -1, data.corrected_name,
484 data.original_name, &next_available_index);
488 #if !defined(NDEBUG)
489 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
490 switches::kEnableGPUServiceLoggingGPU)) {
491 DVLOG(1) << "----: uniforms for service_id: " << service_id();
492 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
493 const UniformInfo& info = uniform_infos_[ii];
494 if (info.IsValid()) {
495 DVLOG(1) << ii << ": loc = " << info.element_locations[0]
496 << ", size = " << info.size
497 << ", type = " << GLES2Util::GetStringEnum(info.type)
498 << ", name = " << info.name;
502 #endif
504 valid_ = true;
507 void Program::ExecuteBindAttribLocationCalls() {
508 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
509 it != bind_attrib_location_map_.end(); ++it) {
510 const std::string* mapped_name = GetAttribMappedName(it->first);
511 if (mapped_name)
512 glBindAttribLocation(service_id_, it->second, mapped_name->c_str());
516 bool Program::Link(ShaderManager* manager,
517 Program::VaryingsPackingOption varyings_packing_option,
518 const ShaderCacheCallback& shader_callback) {
519 ClearLinkStatus();
521 if (!AttachedShadersExist()) {
522 set_log_info("missing shaders");
523 return false;
526 TimeTicks before_time = TimeTicks::Now();
527 bool link = true;
528 ProgramCache* cache = manager_->program_cache_;
529 if (cache) {
530 DCHECK(!attached_shaders_[0]->last_compiled_source().empty() &&
531 !attached_shaders_[1]->last_compiled_source().empty());
532 ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
533 attached_shaders_[0]->last_compiled_signature(),
534 attached_shaders_[1]->last_compiled_signature(),
535 &bind_attrib_location_map_);
537 if (status == ProgramCache::LINK_SUCCEEDED) {
538 ProgramCache::ProgramLoadResult success =
539 cache->LoadLinkedProgram(service_id(),
540 attached_shaders_[0].get(),
541 attached_shaders_[1].get(),
542 &bind_attrib_location_map_,
543 shader_callback);
544 link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
545 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
549 if (link) {
550 CompileAttachedShaders();
552 if (!CanLink()) {
553 set_log_info("invalid shaders");
554 return false;
556 if (DetectAttribLocationBindingConflicts()) {
557 set_log_info("glBindAttribLocation() conflicts");
558 return false;
560 std::string conflicting_name;
561 if (DetectUniformsMismatch(&conflicting_name)) {
562 std::string info_log = "Uniforms with the same name but different "
563 "type/precision: " + conflicting_name;
564 set_log_info(ProcessLogInfo(info_log).c_str());
565 return false;
567 if (DetectVaryingsMismatch(&conflicting_name)) {
568 std::string info_log = "Varyings with the same name but different type, "
569 "or statically used varyings in fragment shader "
570 "are not declared in vertex shader: " +
571 conflicting_name;
572 set_log_info(ProcessLogInfo(info_log).c_str());
573 return false;
575 if (DetectBuiltInInvariantConflicts()) {
576 set_log_info("Invariant settings for certain built-in varyings "
577 "have to match");
578 return false;
580 if (DetectGlobalNameConflicts(&conflicting_name)) {
581 std::string info_log = "Name conflicts between an uniform and an "
582 "attribute: " + conflicting_name;
583 set_log_info(ProcessLogInfo(info_log).c_str());
584 return false;
586 if (!CheckVaryingsPacking(varyings_packing_option)) {
587 set_log_info("Varyings over maximum register limit");
588 return false;
591 ExecuteBindAttribLocationCalls();
592 before_time = TimeTicks::Now();
593 if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
594 glProgramParameteri(service_id(),
595 PROGRAM_BINARY_RETRIEVABLE_HINT,
596 GL_TRUE);
598 glLinkProgram(service_id());
601 GLint success = 0;
602 glGetProgramiv(service_id(), GL_LINK_STATUS, &success);
603 if (success == GL_TRUE) {
604 Update();
605 if (link) {
606 if (cache) {
607 cache->SaveLinkedProgram(service_id(),
608 attached_shaders_[0].get(),
609 attached_shaders_[1].get(),
610 &bind_attrib_location_map_,
611 shader_callback);
613 UMA_HISTOGRAM_CUSTOM_COUNTS(
614 "GPU.ProgramCache.BinaryCacheMissTime",
615 static_cast<base::HistogramBase::Sample>(
616 (TimeTicks::Now() - before_time).InMicroseconds()),
618 static_cast<base::HistogramBase::Sample>(
619 TimeDelta::FromSeconds(10).InMicroseconds()),
620 50);
621 } else {
622 UMA_HISTOGRAM_CUSTOM_COUNTS(
623 "GPU.ProgramCache.BinaryCacheHitTime",
624 static_cast<base::HistogramBase::Sample>(
625 (TimeTicks::Now() - before_time).InMicroseconds()),
627 static_cast<base::HistogramBase::Sample>(
628 TimeDelta::FromSeconds(1).InMicroseconds()),
629 50);
631 } else {
632 UpdateLogInfo();
634 return success == GL_TRUE;
637 void Program::Validate() {
638 if (!IsValid()) {
639 set_log_info("program not linked");
640 return;
642 glValidateProgram(service_id());
643 UpdateLogInfo();
646 GLint Program::GetUniformFakeLocation(
647 const std::string& name) const {
648 bool getting_array_location = false;
649 size_t open_pos = std::string::npos;
650 int index = 0;
651 if (!GLES2Util::ParseUniformName(
652 name, &open_pos, &index, &getting_array_location)) {
653 return -1;
655 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
656 const UniformInfo& info = uniform_infos_[ii];
657 if (!info.IsValid()) {
658 continue;
660 if (info.name == name ||
661 (info.is_array &&
662 info.name.compare(0, info.name.size() - 3, name) == 0)) {
663 return info.fake_location_base;
664 } else if (getting_array_location && info.is_array) {
665 // Look for an array specification.
666 size_t open_pos_2 = info.name.find_last_of('[');
667 if (open_pos_2 == open_pos &&
668 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
669 if (index >= 0 && index < info.size) {
670 DCHECK_GT(static_cast<int>(info.element_locations.size()), index);
671 if (info.element_locations[index] == -1)
672 return -1;
673 return ProgramManager::MakeFakeLocation(
674 info.fake_location_base, index);
679 return -1;
682 GLint Program::GetAttribLocation(
683 const std::string& original_name) const {
684 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
685 const VertexAttrib& info = attrib_infos_[ii];
686 if (info.name == original_name) {
687 return info.location;
690 return -1;
693 const Program::UniformInfo*
694 Program::GetUniformInfoByFakeLocation(
695 GLint fake_location, GLint* real_location, GLint* array_index) const {
696 DCHECK(real_location);
697 DCHECK(array_index);
698 if (fake_location < 0) {
699 return NULL;
702 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
703 if (uniform_index >= 0 &&
704 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
705 const UniformInfo& uniform_info = uniform_infos_[uniform_index];
706 if (!uniform_info.IsValid()) {
707 return NULL;
709 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
710 if (element_index < uniform_info.size) {
711 *real_location = uniform_info.element_locations[element_index];
712 *array_index = element_index;
713 return &uniform_info;
716 return NULL;
719 const std::string* Program::GetAttribMappedName(
720 const std::string& original_name) const {
721 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
722 Shader* shader = attached_shaders_[ii].get();
723 if (shader) {
724 const std::string* mapped_name =
725 shader->GetAttribMappedName(original_name);
726 if (mapped_name)
727 return mapped_name;
730 return NULL;
733 const std::string* Program::GetOriginalNameFromHashedName(
734 const std::string& hashed_name) const {
735 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
736 Shader* shader = attached_shaders_[ii].get();
737 if (shader) {
738 const std::string* original_name =
739 shader->GetOriginalNameFromHashedName(hashed_name);
740 if (original_name)
741 return original_name;
744 return NULL;
747 bool Program::SetUniformLocationBinding(
748 const std::string& name, GLint location) {
749 std::string short_name;
750 int element_index = 0;
751 if (!GetUniformNameSansElement(name, &element_index, &short_name) ||
752 element_index != 0) {
753 return false;
756 bind_uniform_location_map_[short_name] = location;
757 return true;
760 // Note: This is only valid to call right after a program has been linked
761 // successfully.
762 void Program::GetCorrectedUniformData(
763 const std::string& name,
764 std::string* corrected_name, std::string* original_name,
765 GLsizei* size, GLenum* type) const {
766 DCHECK(corrected_name && original_name && size && type);
767 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
768 Shader* shader = attached_shaders_[ii].get();
769 if (!shader)
770 continue;
771 const sh::ShaderVariable* info = NULL;
772 const sh::Uniform* uniform = shader->GetUniformInfo(name);
773 bool found = false;
774 if (uniform)
775 found = uniform->findInfoByMappedName(name, &info, original_name);
776 if (found) {
777 const std::string kArraySpec("[0]");
778 if (info->arraySize > 0 && !EndsWith(name, kArraySpec, true)) {
779 *corrected_name = name + kArraySpec;
780 *original_name += kArraySpec;
781 } else {
782 *corrected_name = name;
784 *type = info->type;
785 *size = std::max(1u, info->arraySize);
786 return;
789 // TODO(zmo): this path should never be reached unless there is a serious
790 // bug in the driver or in ANGLE translator.
791 *corrected_name = name;
792 *original_name = name;
795 void Program::GetVertexAttribData(
796 const std::string& name, std::string* original_name, GLenum* type) const {
797 DCHECK(original_name);
798 DCHECK(type);
799 Shader* shader = attached_shaders_[ShaderTypeToIndex(GL_VERTEX_SHADER)].get();
800 if (shader) {
801 // Vertex attributes can not be arrays or structs (GLSL ES 3.00.4, section
802 // 4.3.4, "Input Variables"), so the top level sh::Attribute returns the
803 // information we need.
804 const sh::Attribute* info = shader->GetAttribInfo(name);
805 if (info) {
806 *original_name = info->name;
807 *type = info->type;
808 return;
811 // TODO(zmo): this path should never be reached unless there is a serious
812 // bug in the driver or in ANGLE translator.
813 *original_name = name;
816 bool Program::AddUniformInfo(
817 GLsizei size, GLenum type, GLint location, GLint fake_base_location,
818 const std::string& name, const std::string& original_name,
819 size_t* next_available_index) {
820 DCHECK(next_available_index);
821 const char* kArraySpec = "[0]";
822 size_t uniform_index =
823 fake_base_location >= 0 ? fake_base_location : *next_available_index;
824 if (uniform_infos_.size() < uniform_index + 1) {
825 uniform_infos_.resize(uniform_index + 1);
828 // return if this location is already in use.
829 if (uniform_infos_[uniform_index].IsValid()) {
830 DCHECK_GE(fake_base_location, 0);
831 return false;
834 uniform_infos_[uniform_index] = UniformInfo(
835 size, type, uniform_index, original_name);
836 ++num_uniforms_;
838 UniformInfo& info = uniform_infos_[uniform_index];
839 info.element_locations.resize(size);
840 info.element_locations[0] = location;
841 DCHECK_GE(size, 0);
842 size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
843 info.texture_units.clear();
844 info.texture_units.resize(num_texture_units, 0);
846 if (size > 1) {
847 // Go through the array element locations looking for a match.
848 // We can skip the first element because it's the same as the
849 // the location without the array operators.
850 size_t array_pos = name.rfind(kArraySpec);
851 std::string base_name = name;
852 if (name.size() > 3) {
853 if (array_pos != name.size() - 3) {
854 info.name = name + kArraySpec;
855 } else {
856 base_name = name.substr(0, name.size() - 3);
859 for (GLsizei ii = 1; ii < info.size; ++ii) {
860 std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
861 info.element_locations[ii] =
862 glGetUniformLocation(service_id_, element_name.c_str());
866 info.is_array =
867 (size > 1 ||
868 (info.name.size() > 3 &&
869 info.name.rfind(kArraySpec) == info.name.size() - 3));
871 if (info.IsSampler()) {
872 sampler_indices_.push_back(info.fake_location_base);
874 max_uniform_name_length_ =
875 std::max(max_uniform_name_length_,
876 static_cast<GLsizei>(info.name.size()));
878 while (*next_available_index < uniform_infos_.size() &&
879 uniform_infos_[*next_available_index].IsValid()) {
880 *next_available_index = *next_available_index + 1;
883 return true;
886 const Program::UniformInfo*
887 Program::GetUniformInfo(
888 GLint index) const {
889 if (static_cast<size_t>(index) >= uniform_infos_.size()) {
890 return NULL;
893 const UniformInfo& info = uniform_infos_[index];
894 return info.IsValid() ? &info : NULL;
897 bool Program::SetSamplers(
898 GLint num_texture_units, GLint fake_location,
899 GLsizei count, const GLint* value) {
900 if (fake_location < 0) {
901 return true;
903 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
904 if (uniform_index >= 0 &&
905 static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
906 UniformInfo& info = uniform_infos_[uniform_index];
907 if (!info.IsValid()) {
908 return false;
910 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
911 if (element_index < info.size) {
912 count = std::min(info.size - element_index, count);
913 if (info.IsSampler() && count > 0) {
914 for (GLsizei ii = 0; ii < count; ++ii) {
915 if (value[ii] < 0 || value[ii] >= num_texture_units) {
916 return false;
919 std::copy(value, value + count,
920 info.texture_units.begin() + element_index);
921 return true;
925 return true;
928 void Program::GetProgramiv(GLenum pname, GLint* params) {
929 switch (pname) {
930 case GL_ACTIVE_ATTRIBUTES:
931 *params = attrib_infos_.size();
932 break;
933 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
934 // Notice +1 to accomodate NULL terminator.
935 *params = max_attrib_name_length_ + 1;
936 break;
937 case GL_ACTIVE_UNIFORMS:
938 *params = num_uniforms_;
939 break;
940 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
941 // Notice +1 to accomodate NULL terminator.
942 *params = max_uniform_name_length_ + 1;
943 break;
944 case GL_LINK_STATUS:
945 *params = link_status_;
946 break;
947 case GL_INFO_LOG_LENGTH:
948 // Notice +1 to accomodate NULL terminator.
949 *params = log_info_.get() ? (log_info_->size() + 1) : 0;
950 break;
951 case GL_DELETE_STATUS:
952 *params = deleted_;
953 break;
954 case GL_VALIDATE_STATUS:
955 if (!IsValid()) {
956 *params = GL_FALSE;
957 } else {
958 glGetProgramiv(service_id_, pname, params);
960 break;
961 default:
962 glGetProgramiv(service_id_, pname, params);
963 break;
967 bool Program::AttachShader(
968 ShaderManager* shader_manager,
969 Shader* shader) {
970 DCHECK(shader_manager);
971 DCHECK(shader);
972 int index = ShaderTypeToIndex(shader->shader_type());
973 if (attached_shaders_[index].get() != NULL) {
974 return false;
976 attached_shaders_[index] = scoped_refptr<Shader>(shader);
977 shader_manager->UseShader(shader);
978 return true;
981 bool Program::DetachShader(
982 ShaderManager* shader_manager,
983 Shader* shader) {
984 DCHECK(shader_manager);
985 DCHECK(shader);
986 if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() !=
987 shader) {
988 return false;
990 attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL;
991 shader_manager->UnuseShader(shader);
992 return true;
995 void Program::DetachShaders(ShaderManager* shader_manager) {
996 DCHECK(shader_manager);
997 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
998 if (attached_shaders_[ii].get()) {
999 DetachShader(shader_manager, attached_shaders_[ii].get());
1004 void Program::CompileAttachedShaders() {
1005 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1006 Shader* shader = attached_shaders_[ii].get();
1007 if (shader) {
1008 shader->DoCompile();
1013 bool Program::AttachedShadersExist() const {
1014 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1015 if (!attached_shaders_[ii].get())
1016 return false;
1018 return true;
1021 bool Program::CanLink() const {
1022 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1023 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid()) {
1024 return false;
1027 return true;
1030 bool Program::DetectAttribLocationBindingConflicts() const {
1031 std::set<GLint> location_binding_used;
1032 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
1033 it != bind_attrib_location_map_.end(); ++it) {
1034 // Find out if an attribute is statically used in this program's shaders.
1035 const sh::Attribute* attrib = NULL;
1036 const std::string* mapped_name = GetAttribMappedName(it->first);
1037 if (!mapped_name)
1038 continue;
1039 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1040 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid())
1041 continue;
1042 attrib = attached_shaders_[ii]->GetAttribInfo(*mapped_name);
1043 if (attrib) {
1044 if (attrib->staticUse)
1045 break;
1046 else
1047 attrib = NULL;
1050 if (attrib) {
1051 size_t num_of_locations = 1;
1052 switch (attrib->type) {
1053 case GL_FLOAT_MAT2:
1054 num_of_locations = 2;
1055 break;
1056 case GL_FLOAT_MAT3:
1057 num_of_locations = 3;
1058 break;
1059 case GL_FLOAT_MAT4:
1060 num_of_locations = 4;
1061 break;
1062 default:
1063 break;
1065 for (size_t ii = 0; ii < num_of_locations; ++ii) {
1066 GLint loc = it->second + ii;
1067 std::pair<std::set<GLint>::iterator, bool> result =
1068 location_binding_used.insert(loc);
1069 if (!result.second)
1070 return true;
1074 return false;
1077 bool Program::DetectUniformsMismatch(std::string* conflicting_name) const {
1078 typedef std::map<std::string, const sh::Uniform*> UniformPointerMap;
1079 UniformPointerMap uniform_pointer_map;
1080 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
1081 const UniformMap& shader_uniforms = attached_shaders_[ii]->uniform_map();
1082 for (UniformMap::const_iterator iter = shader_uniforms.begin();
1083 iter != shader_uniforms.end(); ++iter) {
1084 const std::string& name = iter->first;
1085 UniformPointerMap::iterator hit = uniform_pointer_map.find(name);
1086 if (hit == uniform_pointer_map.end()) {
1087 uniform_pointer_map[name] = &(iter->second);
1088 } else {
1089 // If a uniform is in the map, i.e., it has already been declared by
1090 // another shader, then the type, precision, etc. must match.
1091 if (hit->second->isSameUniformAtLinkTime(iter->second))
1092 continue;
1093 *conflicting_name = name;
1094 return true;
1098 return false;
1101 bool Program::DetectVaryingsMismatch(std::string* conflicting_name) const {
1102 DCHECK(attached_shaders_[0].get() &&
1103 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1104 attached_shaders_[1].get() &&
1105 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1106 const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
1107 const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
1109 for (VaryingMap::const_iterator iter = fragment_varyings->begin();
1110 iter != fragment_varyings->end(); ++iter) {
1111 const std::string& name = iter->first;
1112 if (IsBuiltInFragmentVarying(name))
1113 continue;
1115 VaryingMap::const_iterator hit = vertex_varyings->find(name);
1116 if (hit == vertex_varyings->end()) {
1117 if (iter->second.staticUse) {
1118 *conflicting_name = name;
1119 return true;
1121 continue;
1124 if (!hit->second.isSameVaryingAtLinkTime(iter->second)) {
1125 *conflicting_name = name;
1126 return true;
1130 return false;
1133 bool Program::DetectBuiltInInvariantConflicts() const {
1134 DCHECK(attached_shaders_[0].get() &&
1135 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1136 attached_shaders_[1].get() &&
1137 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1138 const VaryingMap& vertex_varyings = attached_shaders_[0]->varying_map();
1139 const VaryingMap& fragment_varyings = attached_shaders_[1]->varying_map();
1141 bool gl_position_invariant = IsBuiltInInvariant(
1142 vertex_varyings, "gl_Position");
1143 bool gl_point_size_invariant = IsBuiltInInvariant(
1144 vertex_varyings, "gl_PointSize");
1146 bool gl_frag_coord_invariant = IsBuiltInInvariant(
1147 fragment_varyings, "gl_FragCoord");
1148 bool gl_point_coord_invariant = IsBuiltInInvariant(
1149 fragment_varyings, "gl_PointCoord");
1151 return ((gl_frag_coord_invariant && !gl_position_invariant) ||
1152 (gl_point_coord_invariant && !gl_point_size_invariant));
1155 bool Program::DetectGlobalNameConflicts(std::string* conflicting_name) const {
1156 DCHECK(attached_shaders_[0].get() &&
1157 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1158 attached_shaders_[1].get() &&
1159 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1160 const UniformMap* uniforms[2];
1161 uniforms[0] = &(attached_shaders_[0]->uniform_map());
1162 uniforms[1] = &(attached_shaders_[1]->uniform_map());
1163 const AttributeMap* attribs =
1164 &(attached_shaders_[0]->attrib_map());
1166 for (AttributeMap::const_iterator iter = attribs->begin();
1167 iter != attribs->end(); ++iter) {
1168 for (int ii = 0; ii < 2; ++ii) {
1169 if (uniforms[ii]->find(iter->first) != uniforms[ii]->end()) {
1170 *conflicting_name = iter->first;
1171 return true;
1175 return false;
1178 bool Program::CheckVaryingsPacking(
1179 Program::VaryingsPackingOption option) const {
1180 DCHECK(attached_shaders_[0].get() &&
1181 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
1182 attached_shaders_[1].get() &&
1183 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
1184 const VaryingMap* vertex_varyings = &(attached_shaders_[0]->varying_map());
1185 const VaryingMap* fragment_varyings = &(attached_shaders_[1]->varying_map());
1187 std::map<std::string, ShVariableInfo> combined_map;
1189 for (VaryingMap::const_iterator iter = fragment_varyings->begin();
1190 iter != fragment_varyings->end(); ++iter) {
1191 if (!iter->second.staticUse && option == kCountOnlyStaticallyUsed)
1192 continue;
1193 if (!IsBuiltInFragmentVarying(iter->first)) {
1194 VaryingMap::const_iterator vertex_iter =
1195 vertex_varyings->find(iter->first);
1196 if (vertex_iter == vertex_varyings->end() ||
1197 (!vertex_iter->second.staticUse &&
1198 option == kCountOnlyStaticallyUsed))
1199 continue;
1202 ShVariableInfo var;
1203 var.type = static_cast<sh::GLenum>(iter->second.type);
1204 var.size = std::max(1u, iter->second.arraySize);
1205 combined_map[iter->first] = var;
1208 if (combined_map.size() == 0)
1209 return true;
1210 scoped_ptr<ShVariableInfo[]> variables(
1211 new ShVariableInfo[combined_map.size()]);
1212 size_t index = 0;
1213 for (std::map<std::string, ShVariableInfo>::const_iterator iter =
1214 combined_map.begin();
1215 iter != combined_map.end(); ++iter) {
1216 variables[index].type = iter->second.type;
1217 variables[index].size = iter->second.size;
1218 ++index;
1220 return ShCheckVariablesWithinPackingLimits(
1221 static_cast<int>(manager_->max_varying_vectors()),
1222 variables.get(),
1223 combined_map.size());
1226 void Program::GetProgramInfo(
1227 ProgramManager* manager, CommonDecoder::Bucket* bucket) const {
1228 // NOTE: It seems to me the math in here does not need check for overflow
1229 // because the data being calucated from has various small limits. The max
1230 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1231 // of an identifier is 256 characters.
1232 uint32 num_locations = 0;
1233 uint32 total_string_size = 0;
1235 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1236 const VertexAttrib& info = attrib_infos_[ii];
1237 num_locations += 1;
1238 total_string_size += info.name.size();
1241 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1242 const UniformInfo& info = uniform_infos_[ii];
1243 if (info.IsValid()) {
1244 num_locations += info.element_locations.size();
1245 total_string_size += info.name.size();
1249 uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
1250 uint32 input_size = num_inputs * sizeof(ProgramInput);
1251 uint32 location_size = num_locations * sizeof(int32);
1252 uint32 size = sizeof(ProgramInfoHeader) +
1253 input_size + location_size + total_string_size;
1255 bucket->SetSize(size);
1256 ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
1257 ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
1258 sizeof(ProgramInfoHeader), input_size);
1259 int32* locations = bucket->GetDataAs<int32*>(
1260 sizeof(ProgramInfoHeader) + input_size, location_size);
1261 char* strings = bucket->GetDataAs<char*>(
1262 sizeof(ProgramInfoHeader) + input_size + location_size,
1263 total_string_size);
1264 DCHECK(header);
1265 DCHECK(inputs);
1266 DCHECK(locations);
1267 DCHECK(strings);
1269 header->link_status = link_status_;
1270 header->num_attribs = attrib_infos_.size();
1271 header->num_uniforms = num_uniforms_;
1273 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
1274 const VertexAttrib& info = attrib_infos_[ii];
1275 inputs->size = info.size;
1276 inputs->type = info.type;
1277 inputs->location_offset = ComputeOffset(header, locations);
1278 inputs->name_offset = ComputeOffset(header, strings);
1279 inputs->name_length = info.name.size();
1280 *locations++ = info.location;
1281 memcpy(strings, info.name.c_str(), info.name.size());
1282 strings += info.name.size();
1283 ++inputs;
1286 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
1287 const UniformInfo& info = uniform_infos_[ii];
1288 if (info.IsValid()) {
1289 inputs->size = info.size;
1290 inputs->type = info.type;
1291 inputs->location_offset = ComputeOffset(header, locations);
1292 inputs->name_offset = ComputeOffset(header, strings);
1293 inputs->name_length = info.name.size();
1294 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
1295 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
1296 if (info.element_locations[jj] == -1)
1297 *locations++ = -1;
1298 else
1299 *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
1301 memcpy(strings, info.name.c_str(), info.name.size());
1302 strings += info.name.size();
1303 ++inputs;
1307 DCHECK_EQ(ComputeOffset(header, strings), size);
1310 bool Program::GetUniformBlocks(CommonDecoder::Bucket* bucket) const {
1311 // The data is packed into the bucket in the following order
1312 // 1) header
1313 // 2) N entries of block data (except for name and indices)
1314 // 3) name1, indices1, name2, indices2, ..., nameN, indicesN
1316 // We query all the data directly through GL calls, assuming they are
1317 // cheap through MANGLE.
1319 DCHECK(bucket);
1320 GLuint program = service_id();
1322 uint32_t header_size = sizeof(UniformBlocksHeader);
1323 bucket->SetSize(header_size); // In case we fail.
1325 uint32_t num_uniform_blocks = 0;
1326 GLint param = GL_FALSE;
1327 // We assume program is a valid program service id.
1328 glGetProgramiv(program, GL_LINK_STATUS, &param);
1329 if (param == GL_TRUE) {
1330 param = 0;
1331 glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &param);
1332 num_uniform_blocks = static_cast<uint32_t>(param);
1334 if (num_uniform_blocks == 0) {
1335 // Although spec allows an implementation to return uniform block info
1336 // even if a link fails, for consistency, we disallow that.
1337 return true;
1340 std::vector<UniformBlockInfo> blocks(num_uniform_blocks);
1341 base::CheckedNumeric<uint32_t> size = sizeof(UniformBlockInfo);
1342 size *= num_uniform_blocks;
1343 uint32_t entry_size = size.ValueOrDefault(0);
1344 size += header_size;
1345 std::vector<std::string> names(num_uniform_blocks);
1346 GLint max_name_length = 0;
1347 glGetProgramiv(
1348 program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_name_length);
1349 std::vector<GLchar> buffer(max_name_length);
1350 GLsizei length;
1351 for (uint32_t ii = 0; ii < num_uniform_blocks; ++ii) {
1352 param = 0;
1353 glGetActiveUniformBlockiv(program, ii, GL_UNIFORM_BLOCK_BINDING, &param);
1354 blocks[ii].binding = static_cast<uint32_t>(param);
1356 param = 0;
1357 glGetActiveUniformBlockiv(program, ii, GL_UNIFORM_BLOCK_DATA_SIZE, &param);
1358 blocks[ii].data_size = static_cast<uint32_t>(param);
1360 blocks[ii].name_offset = size.ValueOrDefault(0);
1361 param = 0;
1362 glGetActiveUniformBlockiv(
1363 program, ii, GL_UNIFORM_BLOCK_NAME_LENGTH, &param);
1364 DCHECK_GE(max_name_length, param);
1365 memset(&buffer[0], 0, param);
1366 length = 0;
1367 glGetActiveUniformBlockName(
1368 program, ii, static_cast<GLsizei>(param), &length, &buffer[0]);
1369 DCHECK_EQ(param, length + 1);
1370 names[ii] = std::string(&buffer[0], length);
1371 // TODO(zmo): optimize the name mapping lookup.
1372 const std::string* original_name = GetOriginalNameFromHashedName(names[ii]);
1373 if (original_name)
1374 names[ii] = *original_name;
1375 blocks[ii].name_length = names[ii].size() + 1;
1376 size += blocks[ii].name_length;
1378 param = 0;
1379 glGetActiveUniformBlockiv(
1380 program, ii, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &param);
1381 blocks[ii].active_uniforms = static_cast<uint32_t>(param);
1382 blocks[ii].active_uniform_offset = size.ValueOrDefault(0);
1383 base::CheckedNumeric<uint32_t> indices_size = blocks[ii].active_uniforms;
1384 indices_size *= sizeof(uint32_t);
1385 if (!indices_size.IsValid())
1386 return false;
1387 size += indices_size.ValueOrDefault(0);
1389 param = 0;
1390 glGetActiveUniformBlockiv(
1391 program, ii, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &param);
1392 blocks[ii].referenced_by_vertex_shader = static_cast<uint32_t>(param);
1394 param = 0;
1395 glGetActiveUniformBlockiv(
1396 program, ii, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &param);
1397 blocks[ii].referenced_by_fragment_shader = static_cast<uint32_t>(param);
1399 if (!size.IsValid())
1400 return false;
1401 uint32_t total_size = size.ValueOrDefault(0);
1402 DCHECK_LE(header_size + entry_size, total_size);
1403 uint32_t data_size = total_size - header_size - entry_size;
1405 bucket->SetSize(total_size);
1406 UniformBlocksHeader* header =
1407 bucket->GetDataAs<UniformBlocksHeader*>(0, header_size);
1408 UniformBlockInfo* entries = bucket->GetDataAs<UniformBlockInfo*>(
1409 header_size, entry_size);
1410 char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size);
1411 DCHECK(header);
1412 DCHECK(entries);
1413 DCHECK(data);
1415 // Copy over data for the header and entries.
1416 header->num_uniform_blocks = num_uniform_blocks;
1417 memcpy(entries, &blocks[0], entry_size);
1419 std::vector<GLint> params;
1420 for (uint32_t ii = 0; ii < num_uniform_blocks; ++ii) {
1421 // Get active uniform name.
1422 memcpy(data, names[ii].c_str(), names[ii].length() + 1);
1423 data += names[ii].length() + 1;
1425 // Get active uniform indices.
1426 if (params.size() < blocks[ii].active_uniforms)
1427 params.resize(blocks[ii].active_uniforms);
1428 uint32_t num_bytes = blocks[ii].active_uniforms * sizeof(GLint);
1429 memset(&params[0], 0, num_bytes);
1430 glGetActiveUniformBlockiv(
1431 program, ii, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, &params[0]);
1432 uint32_t* indices = reinterpret_cast<uint32_t*>(data);
1433 for (uint32_t uu = 0; uu < blocks[ii].active_uniforms; ++uu) {
1434 indices[uu] = static_cast<uint32_t>(params[uu]);
1436 data += num_bytes;
1438 DCHECK_EQ(ComputeOffset(header, data), total_size);
1439 return true;
1442 bool Program::GetTransformFeedbackVaryings(
1443 CommonDecoder::Bucket* bucket) const {
1444 // The data is packed into the bucket in the following order
1445 // 1) header
1446 // 2) N entries of varying data (except for name)
1447 // 3) name1, name2, ..., nameN
1449 // We query all the data directly through GL calls, assuming they are
1450 // cheap through MANGLE.
1452 DCHECK(bucket);
1453 GLuint program = service_id();
1455 uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader);
1456 bucket->SetSize(header_size); // In case we fail.
1458 uint32_t num_transform_feedback_varyings = 0;
1459 GLint param = GL_FALSE;
1460 // We assume program is a valid program service id.
1461 glGetProgramiv(program, GL_LINK_STATUS, &param);
1462 if (param == GL_TRUE) {
1463 param = 0;
1464 glGetProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &param);
1465 num_transform_feedback_varyings = static_cast<uint32_t>(param);
1467 if (num_transform_feedback_varyings == 0) {
1468 return true;
1471 std::vector<TransformFeedbackVaryingInfo> varyings(
1472 num_transform_feedback_varyings);
1473 base::CheckedNumeric<uint32_t> size = sizeof(TransformFeedbackVaryingInfo);
1474 size *= num_transform_feedback_varyings;
1475 uint32_t entry_size = size.ValueOrDefault(0);
1476 size += header_size;
1477 std::vector<std::string> names(num_transform_feedback_varyings);
1478 GLint max_name_length = 0;
1479 glGetProgramiv(
1480 program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &max_name_length);
1481 if (max_name_length < 1)
1482 max_name_length = 1;
1483 std::vector<char> buffer(max_name_length);
1484 for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) {
1485 GLsizei var_size = 0;
1486 GLsizei var_name_length = 0;
1487 GLenum var_type = 0;
1488 glGetTransformFeedbackVarying(
1489 program, ii, max_name_length,
1490 &var_name_length, &var_size, &var_type, &buffer[0]);
1491 varyings[ii].size = static_cast<uint32_t>(var_size);
1492 varyings[ii].type = static_cast<uint32_t>(var_type);
1493 varyings[ii].name_offset = static_cast<uint32_t>(size.ValueOrDefault(0));
1494 DCHECK_GT(max_name_length, var_name_length);
1495 names[ii] = std::string(&buffer[0], var_name_length);
1496 // TODO(zmo): optimize the name mapping lookup.
1497 const std::string* original_name = GetOriginalNameFromHashedName(names[ii]);
1498 if (original_name)
1499 names[ii] = *original_name;
1500 varyings[ii].name_length = names[ii].size() + 1;
1501 size += names[ii].size();
1502 size += 1;
1504 if (!size.IsValid())
1505 return false;
1506 uint32_t total_size = size.ValueOrDefault(0);
1507 DCHECK_LE(header_size + entry_size, total_size);
1508 uint32_t data_size = total_size - header_size - entry_size;
1510 bucket->SetSize(total_size);
1511 TransformFeedbackVaryingsHeader* header =
1512 bucket->GetDataAs<TransformFeedbackVaryingsHeader*>(0, header_size);
1513 TransformFeedbackVaryingInfo* entries =
1514 bucket->GetDataAs<TransformFeedbackVaryingInfo*>(header_size, entry_size);
1515 char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size);
1516 DCHECK(header);
1517 DCHECK(entries);
1518 DCHECK(data);
1520 // Copy over data for the header and entries.
1521 header->num_transform_feedback_varyings = num_transform_feedback_varyings;
1522 memcpy(entries, &varyings[0], entry_size);
1524 for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) {
1525 memcpy(data, names[ii].c_str(), names[ii].length() + 1);
1526 data += names[ii].length() + 1;
1528 DCHECK_EQ(ComputeOffset(header, data), total_size);
1529 return true;
1532 bool Program::GetUniformsES3(CommonDecoder::Bucket* bucket) const {
1533 // The data is packed into the bucket in the following order
1534 // 1) header
1535 // 2) N entries of UniformES3Info
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(UniformsES3Header);
1544 bucket->SetSize(header_size); // In case we fail.
1546 GLsizei count = 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_ACTIVE_UNIFORMS, &count);
1554 if (count == 0) {
1555 return true;
1558 base::CheckedNumeric<uint32_t> size = sizeof(UniformES3Info);
1559 size *= count;
1560 uint32_t entry_size = size.ValueOrDefault(0);
1561 size += header_size;
1562 if (!size.IsValid())
1563 return false;
1564 uint32_t total_size = size.ValueOrDefault(0);
1565 bucket->SetSize(total_size);
1566 UniformsES3Header* header =
1567 bucket->GetDataAs<UniformsES3Header*>(0, header_size);
1568 DCHECK(header);
1569 header->num_uniforms = static_cast<uint32_t>(count);
1571 // Instead of GetDataAs<UniformES3Info*>, we do GetDataAs<int32_t>. This is
1572 // because struct UniformES3Info is defined as five int32_t.
1573 // By doing this, we can fill the structs through loops.
1574 int32_t* entries =
1575 bucket->GetDataAs<int32_t*>(header_size, entry_size);
1576 DCHECK(entries);
1577 const size_t kStride = sizeof(UniformES3Info) / sizeof(int32_t);
1579 const GLenum kPname[] = {
1580 GL_UNIFORM_BLOCK_INDEX,
1581 GL_UNIFORM_OFFSET,
1582 GL_UNIFORM_ARRAY_STRIDE,
1583 GL_UNIFORM_MATRIX_STRIDE,
1584 GL_UNIFORM_IS_ROW_MAJOR,
1586 const GLint kDefaultValue[] = { -1, -1, -1, -1, 0 };
1587 const size_t kNumPnames = arraysize(kPname);
1588 std::vector<GLuint> indices(count);
1589 for (GLsizei ii = 0; ii < count; ++ii) {
1590 indices[ii] = ii;
1592 std::vector<GLint> params(count);
1593 for (size_t pname_index = 0; pname_index < kNumPnames; ++pname_index) {
1594 for (GLsizei ii = 0; ii < count; ++ii) {
1595 params[ii] = kDefaultValue[pname_index];
1597 glGetActiveUniformsiv(
1598 program, count, &indices[0], kPname[pname_index], &params[0]);
1599 for (GLsizei ii = 0; ii < count; ++ii) {
1600 entries[kStride * ii + pname_index] = params[ii];
1603 return true;
1606 Program::~Program() {
1607 if (manager_) {
1608 if (manager_->have_context_) {
1609 glDeleteProgram(service_id());
1611 manager_->StopTracking(this);
1612 manager_ = NULL;
1617 ProgramManager::ProgramManager(ProgramCache* program_cache,
1618 uint32 max_varying_vectors)
1619 : program_count_(0),
1620 have_context_(true),
1621 program_cache_(program_cache),
1622 max_varying_vectors_(max_varying_vectors) { }
1624 ProgramManager::~ProgramManager() {
1625 DCHECK(programs_.empty());
1628 void ProgramManager::Destroy(bool have_context) {
1629 have_context_ = have_context;
1630 programs_.clear();
1633 void ProgramManager::StartTracking(Program* /* program */) {
1634 ++program_count_;
1637 void ProgramManager::StopTracking(Program* /* program */) {
1638 --program_count_;
1641 Program* ProgramManager::CreateProgram(
1642 GLuint client_id, GLuint service_id) {
1643 std::pair<ProgramMap::iterator, bool> result =
1644 programs_.insert(
1645 std::make_pair(client_id,
1646 scoped_refptr<Program>(
1647 new Program(this, service_id))));
1648 DCHECK(result.second);
1649 return result.first->second.get();
1652 Program* ProgramManager::GetProgram(GLuint client_id) {
1653 ProgramMap::iterator it = programs_.find(client_id);
1654 return it != programs_.end() ? it->second.get() : NULL;
1657 bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
1658 // This doesn't need to be fast. It's only used during slow queries.
1659 for (ProgramMap::const_iterator it = programs_.begin();
1660 it != programs_.end(); ++it) {
1661 if (it->second->service_id() == service_id) {
1662 *client_id = it->first;
1663 return true;
1666 return false;
1669 ProgramCache* ProgramManager::program_cache() const {
1670 return program_cache_;
1673 bool ProgramManager::IsOwned(Program* program) {
1674 for (ProgramMap::iterator it = programs_.begin();
1675 it != programs_.end(); ++it) {
1676 if (it->second.get() == program) {
1677 return true;
1680 return false;
1683 void ProgramManager::RemoveProgramInfoIfUnused(
1684 ShaderManager* shader_manager, Program* program) {
1685 DCHECK(shader_manager);
1686 DCHECK(program);
1687 DCHECK(IsOwned(program));
1688 if (program->IsDeleted() && !program->InUse()) {
1689 program->DetachShaders(shader_manager);
1690 for (ProgramMap::iterator it = programs_.begin();
1691 it != programs_.end(); ++it) {
1692 if (it->second.get() == program) {
1693 programs_.erase(it);
1694 return;
1697 NOTREACHED();
1701 void ProgramManager::MarkAsDeleted(
1702 ShaderManager* shader_manager,
1703 Program* program) {
1704 DCHECK(shader_manager);
1705 DCHECK(program);
1706 DCHECK(IsOwned(program));
1707 program->MarkAsDeleted();
1708 RemoveProgramInfoIfUnused(shader_manager, program);
1711 void ProgramManager::UseProgram(Program* program) {
1712 DCHECK(program);
1713 DCHECK(IsOwned(program));
1714 program->IncUseCount();
1717 void ProgramManager::UnuseProgram(
1718 ShaderManager* shader_manager,
1719 Program* program) {
1720 DCHECK(shader_manager);
1721 DCHECK(program);
1722 DCHECK(IsOwned(program));
1723 program->DecUseCount();
1724 RemoveProgramInfoIfUnused(shader_manager, program);
1727 void ProgramManager::ClearUniforms(Program* program) {
1728 DCHECK(program);
1729 program->ClearUniforms(&zero_);
1732 int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
1733 return index + element * 0x10000;
1736 } // namespace gles2
1737 } // namespace gpu