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"
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
;
37 int ShaderTypeToIndex(GLenum shader_type
) {
38 switch (shader_type
) {
39 case GL_VERTEX_SHADER
:
41 case GL_FRAGMENT_SHADER
:
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
);
56 if (name
.size() < 3 || name
[name
.size() - 1] != ']') {
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) {
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) {
76 index
= index
* 10 + digit
;
78 if (!index
.IsValid()) {
82 *element_index
= index
.ValueOrDie();
83 *new_name
= name
.substr(0, open_pos
);
87 bool IsBuiltInFragmentVarying(const std::string
& name
) {
88 // Built-in variables for fragment shaders.
89 const char* kBuiltInVaryings
[] = {
94 for (size_t ii
= 0; ii
< arraysize(kBuiltInVaryings
); ++ii
) {
95 if (name
== kBuiltInVaryings
[ii
])
101 bool IsBuiltInInvariant(
102 const VaryingMap
& varyings
, const std::string
& name
) {
103 VaryingMap::const_iterator hit
= varyings
.find(name
);
104 if (hit
== varyings
.end())
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()
119 fake_location_base(0),
123 Program::UniformInfo::UniformInfo(GLsizei _size
,
125 int _fake_location_base
,
126 const std::string
& _name
)
130 fake_location_base(_fake_location_base
),
135 accepts_api_type
= kUniform1i
;
138 accepts_api_type
= kUniform2i
;
141 accepts_api_type
= kUniform3i
;
144 accepts_api_type
= kUniform4i
;
148 accepts_api_type
= kUniform1i
| kUniform1f
;
151 accepts_api_type
= kUniform2i
| kUniform2f
;
154 accepts_api_type
= kUniform3i
| kUniform3f
;
157 accepts_api_type
= kUniform4i
| kUniform4f
;
161 accepts_api_type
= kUniform1f
;
164 accepts_api_type
= kUniform2f
;
167 accepts_api_type
= kUniform3f
;
170 accepts_api_type
= kUniform4f
;
174 accepts_api_type
= kUniformMatrix2f
;
177 accepts_api_type
= kUniformMatrix3f
;
180 accepts_api_type
= kUniformMatrix4f
;
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
;
191 NOTREACHED() << "Unhandled UniformInfo type " << type
;
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
)
207 max_attrib_name_length_(0),
208 max_uniform_name_length_(0),
209 service_id_(service_id
),
213 uniforms_cleared_(false),
215 transform_feedback_buffer_mode_(GL_NONE
) {
216 manager_
->StartTracking(this);
219 void Program::Reset() {
221 link_status_
= false;
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
) {
234 re2::StringPiece
input(log
);
235 std::string prior_log
;
236 std::string hashed_name
;
237 while (RE2::Consume(&input
,
238 "(.*?)(webgl_[0123456789abcdefABCDEF]+)",
243 const std::string
* original_name
=
244 GetOriginalNameFromHashedName(hashed_name
);
246 output
+= *original_name
;
248 output
+= hashed_name
;
251 return output
+ input
.as_string();
254 void Program::UpdateLogInfo() {
256 glGetProgramiv(service_id_
, GL_INFO_LOG_LENGTH
, &max_len
);
261 scoped_ptr
<char[]> temp(new char[max_len
]);
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
) {
273 if (uniforms_cleared_
) {
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()) {
282 GLint location
= uniform_info
.element_locations
[0];
283 GLsizei size
= uniform_info
.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
) {
295 glUniform1fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
298 glUniform2fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
301 glUniform3fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
304 glUniform4fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
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
));
316 glUniform2iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
320 glUniform3iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
324 glUniform4iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
328 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
332 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
336 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
340 case GL_UNSIGNED_INT
:
341 glUniform1uiv(location
, size
, reinterpret_cast<const GLuint
*>(zero
));
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
));
358 case GL_UNSIGNED_INT_VEC2
:
359 glUniform2uiv(location
, size
, reinterpret_cast<const GLuint
*>(zero
));
361 case GL_UNSIGNED_INT_VEC3
:
362 glUniform3uiv(location
, size
, reinterpret_cast<const GLuint
*>(zero
));
364 case GL_UNSIGNED_INT_VEC4
:
365 glUniform4uiv(location
, size
, reinterpret_cast<const GLuint
*>(zero
));
367 case GL_FLOAT_MAT2x3
:
368 glUniformMatrix2x3fv(
369 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
371 case GL_FLOAT_MAT3x2
:
372 glUniformMatrix3x2fv(
373 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
375 case GL_FLOAT_MAT2x4
:
376 glUniformMatrix2x4fv(
377 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
379 case GL_FLOAT_MAT4x2
:
380 glUniformMatrix4x2fv(
381 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
383 case GL_FLOAT_MAT3x4
:
384 glUniformMatrix3x4fv(
385 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
387 case GL_FLOAT_MAT4x3
:
388 glUniformMatrix4x3fv(
389 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
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
;
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() {
425 uniforms_cleared_
= false;
426 GLint num_attribs
= 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
) {
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
;
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
;
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
) {
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())) {
517 glGetUniformLocation(service_id_
, data
.queried_name
.c_str());
520 std::string short_name
;
521 int element_index
= 0;
522 bool good
= GetUniformNameSansElement(data
.queried_name
, &element_index
,
525 LocationMap::const_iterator it
= bind_uniform_location_map_
.find(
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
];
539 data
.size
, data
.type
, data
.location
, -1, data
.corrected_name
,
540 data
.original_name
, &next_available_index
);
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
;
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
);
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
) {
577 if (!AttachedShadersExist()) {
578 set_log_info("missing shaders");
582 TimeTicks before_time
= TimeTicks::Now();
584 ProgramCache
* cache
= manager_
->program_cache_
;
586 DCHECK(!attached_shaders_
[0]->last_compiled_source().empty() &&
587 !attached_shaders_
[1]->last_compiled_source().empty());
588 ProgramCache::LinkedProgramStatus status
= cache
->GetLinkedProgramStatus(
589 attached_shaders_
[0]->last_compiled_signature(),
590 attached_shaders_
[1]->last_compiled_signature(),
591 &bind_attrib_location_map_
,
592 transform_feedback_varyings_
,
593 transform_feedback_buffer_mode_
);
595 if (status
== ProgramCache::LINK_SUCCEEDED
) {
596 ProgramCache::ProgramLoadResult success
=
597 cache
->LoadLinkedProgram(service_id(),
598 attached_shaders_
[0].get(),
599 attached_shaders_
[1].get(),
600 &bind_attrib_location_map_
,
601 transform_feedback_varyings_
,
602 transform_feedback_buffer_mode_
,
604 link
= success
!= ProgramCache::PROGRAM_LOAD_SUCCESS
;
605 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link
);
610 CompileAttachedShaders();
613 set_log_info("invalid shaders");
616 if (DetectShaderVersionMismatch()) {
617 set_log_info("Versions of linked shaders have to match.");
620 if (DetectAttribLocationBindingConflicts()) {
621 set_log_info("glBindAttribLocation() conflicts");
624 std::string conflicting_name
;
625 if (DetectUniformsMismatch(&conflicting_name
)) {
626 std::string info_log
= "Uniforms with the same name but different "
627 "type/precision: " + conflicting_name
;
628 set_log_info(ProcessLogInfo(info_log
).c_str());
631 if (DetectVaryingsMismatch(&conflicting_name
)) {
632 std::string info_log
= "Varyings with the same name but different type, "
633 "or statically used varyings in fragment shader "
634 "are not declared in vertex shader: " +
636 set_log_info(ProcessLogInfo(info_log
).c_str());
639 if (DetectBuiltInInvariantConflicts()) {
640 set_log_info("Invariant settings for certain built-in varyings "
644 if (DetectGlobalNameConflicts(&conflicting_name
)) {
645 std::string info_log
= "Name conflicts between an uniform and an "
646 "attribute: " + conflicting_name
;
647 set_log_info(ProcessLogInfo(info_log
).c_str());
650 if (!CheckVaryingsPacking(varyings_packing_option
)) {
651 set_log_info("Varyings over maximum register limit");
655 ExecuteBindAttribLocationCalls();
656 before_time
= TimeTicks::Now();
657 if (cache
&& gfx::g_driver_gl
.ext
.b_GL_ARB_get_program_binary
) {
658 glProgramParameteri(service_id(),
659 PROGRAM_BINARY_RETRIEVABLE_HINT
,
662 glLinkProgram(service_id());
666 glGetProgramiv(service_id(), GL_LINK_STATUS
, &success
);
667 if (success
== GL_TRUE
) {
671 cache
->SaveLinkedProgram(service_id(),
672 attached_shaders_
[0].get(),
673 attached_shaders_
[1].get(),
674 &bind_attrib_location_map_
,
675 transform_feedback_varyings_
,
676 transform_feedback_buffer_mode_
,
679 UMA_HISTOGRAM_CUSTOM_COUNTS(
680 "GPU.ProgramCache.BinaryCacheMissTime",
681 static_cast<base::HistogramBase::Sample
>(
682 (TimeTicks::Now() - before_time
).InMicroseconds()),
684 static_cast<base::HistogramBase::Sample
>(
685 TimeDelta::FromSeconds(10).InMicroseconds()),
688 UMA_HISTOGRAM_CUSTOM_COUNTS(
689 "GPU.ProgramCache.BinaryCacheHitTime",
690 static_cast<base::HistogramBase::Sample
>(
691 (TimeTicks::Now() - before_time
).InMicroseconds()),
693 static_cast<base::HistogramBase::Sample
>(
694 TimeDelta::FromSeconds(1).InMicroseconds()),
700 return success
== GL_TRUE
;
703 void Program::Validate() {
705 set_log_info("program not linked");
708 glValidateProgram(service_id());
712 GLint
Program::GetUniformFakeLocation(
713 const std::string
& name
) const {
714 bool getting_array_location
= false;
715 size_t open_pos
= std::string::npos
;
717 if (!GLES2Util::ParseUniformName(
718 name
, &open_pos
, &index
, &getting_array_location
)) {
721 for (GLuint ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
722 const UniformInfo
& info
= uniform_infos_
[ii
];
723 if (!info
.IsValid()) {
726 if (info
.name
== name
||
728 info
.name
.compare(0, info
.name
.size() - 3, name
) == 0)) {
729 return info
.fake_location_base
;
730 } else if (getting_array_location
&& info
.is_array
) {
731 // Look for an array specification.
732 size_t open_pos_2
= info
.name
.find_last_of('[');
733 if (open_pos_2
== open_pos
&&
734 name
.compare(0, open_pos
, info
.name
, 0, open_pos
) == 0) {
735 if (index
>= 0 && index
< info
.size
) {
736 DCHECK_GT(static_cast<int>(info
.element_locations
.size()), index
);
737 if (info
.element_locations
[index
] == -1)
739 return ProgramManager::MakeFakeLocation(
740 info
.fake_location_base
, index
);
748 GLint
Program::GetAttribLocation(
749 const std::string
& original_name
) const {
750 for (GLuint ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
751 const VertexAttrib
& info
= attrib_infos_
[ii
];
752 if (info
.name
== original_name
) {
753 return info
.location
;
759 const Program::UniformInfo
*
760 Program::GetUniformInfoByFakeLocation(
761 GLint fake_location
, GLint
* real_location
, GLint
* array_index
) const {
762 DCHECK(real_location
);
764 if (fake_location
< 0) {
768 GLint uniform_index
= GetUniformInfoIndexFromFakeLocation(fake_location
);
769 if (uniform_index
>= 0 &&
770 static_cast<size_t>(uniform_index
) < uniform_infos_
.size()) {
771 const UniformInfo
& uniform_info
= uniform_infos_
[uniform_index
];
772 if (!uniform_info
.IsValid()) {
775 GLint element_index
= GetArrayElementIndexFromFakeLocation(fake_location
);
776 if (element_index
< uniform_info
.size
) {
777 *real_location
= uniform_info
.element_locations
[element_index
];
778 *array_index
= element_index
;
779 return &uniform_info
;
785 const std::string
* Program::GetAttribMappedName(
786 const std::string
& original_name
) const {
787 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
788 Shader
* shader
= attached_shaders_
[ii
].get();
790 const std::string
* mapped_name
=
791 shader
->GetAttribMappedName(original_name
);
799 const std::string
* Program::GetOriginalNameFromHashedName(
800 const std::string
& hashed_name
) const {
801 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
802 Shader
* shader
= attached_shaders_
[ii
].get();
804 const std::string
* original_name
=
805 shader
->GetOriginalNameFromHashedName(hashed_name
);
807 return original_name
;
813 bool Program::SetUniformLocationBinding(
814 const std::string
& name
, GLint location
) {
815 std::string short_name
;
816 int element_index
= 0;
817 if (!GetUniformNameSansElement(name
, &element_index
, &short_name
) ||
818 element_index
!= 0) {
822 bind_uniform_location_map_
[short_name
] = location
;
826 // Note: This is only valid to call right after a program has been linked
828 void Program::GetCorrectedUniformData(
829 const std::string
& name
,
830 std::string
* corrected_name
, std::string
* original_name
,
831 GLsizei
* size
, GLenum
* type
) const {
832 DCHECK(corrected_name
&& original_name
&& size
&& type
);
833 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
834 Shader
* shader
= attached_shaders_
[ii
].get();
837 const sh::ShaderVariable
* info
= NULL
;
838 const sh::Uniform
* uniform
= shader
->GetUniformInfo(name
);
841 found
= uniform
->findInfoByMappedName(name
, &info
, original_name
);
843 const std::string
kArraySpec("[0]");
844 if (info
->arraySize
> 0 &&
845 !base::EndsWith(name
, kArraySpec
, base::CompareCase::SENSITIVE
)) {
846 *corrected_name
= name
+ kArraySpec
;
847 *original_name
+= kArraySpec
;
849 *corrected_name
= name
;
852 *size
= std::max(1u, info
->arraySize
);
856 // TODO(zmo): this path should never be reached unless there is a serious
857 // bug in the driver or in ANGLE translator.
858 *corrected_name
= name
;
859 *original_name
= name
;
862 void Program::GetVertexAttribData(
863 const std::string
& name
, std::string
* original_name
, GLenum
* type
) const {
864 DCHECK(original_name
);
866 Shader
* shader
= attached_shaders_
[ShaderTypeToIndex(GL_VERTEX_SHADER
)].get();
868 // Vertex attributes can not be arrays or structs (GLSL ES 3.00.4, section
869 // 4.3.4, "Input Variables"), so the top level sh::Attribute returns the
870 // information we need.
871 const sh::Attribute
* info
= shader
->GetAttribInfo(name
);
873 *original_name
= info
->name
;
878 // TODO(zmo): this path should never be reached unless there is a serious
879 // bug in the driver or in ANGLE translator.
880 *original_name
= name
;
883 bool Program::AddUniformInfo(
884 GLsizei size
, GLenum type
, GLint location
, GLint fake_base_location
,
885 const std::string
& name
, const std::string
& original_name
,
886 size_t* next_available_index
) {
887 DCHECK(next_available_index
);
888 const char* kArraySpec
= "[0]";
889 size_t uniform_index
=
890 fake_base_location
>= 0 ? fake_base_location
: *next_available_index
;
891 if (uniform_infos_
.size() < uniform_index
+ 1) {
892 uniform_infos_
.resize(uniform_index
+ 1);
895 // return if this location is already in use.
896 if (uniform_infos_
[uniform_index
].IsValid()) {
897 DCHECK_GE(fake_base_location
, 0);
901 uniform_infos_
[uniform_index
] = UniformInfo(
902 size
, type
, uniform_index
, original_name
);
905 UniformInfo
& info
= uniform_infos_
[uniform_index
];
906 info
.element_locations
.resize(size
);
907 info
.element_locations
[0] = location
;
909 size_t num_texture_units
= info
.IsSampler() ? static_cast<size_t>(size
) : 0u;
910 info
.texture_units
.clear();
911 info
.texture_units
.resize(num_texture_units
, 0);
914 // Go through the array element locations looking for a match.
915 // We can skip the first element because it's the same as the
916 // the location without the array operators.
917 size_t array_pos
= name
.rfind(kArraySpec
);
918 std::string base_name
= name
;
919 if (name
.size() > 3) {
920 if (array_pos
!= name
.size() - 3) {
921 info
.name
= name
+ kArraySpec
;
923 base_name
= name
.substr(0, name
.size() - 3);
926 for (GLsizei ii
= 1; ii
< info
.size
; ++ii
) {
927 std::string
element_name(base_name
+ "[" + base::IntToString(ii
) + "]");
928 info
.element_locations
[ii
] =
929 glGetUniformLocation(service_id_
, element_name
.c_str());
935 (info
.name
.size() > 3 &&
936 info
.name
.rfind(kArraySpec
) == info
.name
.size() - 3));
938 if (info
.IsSampler()) {
939 sampler_indices_
.push_back(info
.fake_location_base
);
941 max_uniform_name_length_
=
942 std::max(max_uniform_name_length_
,
943 static_cast<GLsizei
>(info
.name
.size()));
945 while (*next_available_index
< uniform_infos_
.size() &&
946 uniform_infos_
[*next_available_index
].IsValid()) {
947 *next_available_index
= *next_available_index
+ 1;
953 const Program::UniformInfo
*
954 Program::GetUniformInfo(
956 if (static_cast<size_t>(index
) >= uniform_infos_
.size()) {
960 const UniformInfo
& info
= uniform_infos_
[index
];
961 return info
.IsValid() ? &info
: NULL
;
964 bool Program::SetSamplers(
965 GLint num_texture_units
, GLint fake_location
,
966 GLsizei count
, const GLint
* value
) {
967 if (fake_location
< 0) {
970 GLint uniform_index
= GetUniformInfoIndexFromFakeLocation(fake_location
);
971 if (uniform_index
>= 0 &&
972 static_cast<size_t>(uniform_index
) < uniform_infos_
.size()) {
973 UniformInfo
& info
= uniform_infos_
[uniform_index
];
974 if (!info
.IsValid()) {
977 GLint element_index
= GetArrayElementIndexFromFakeLocation(fake_location
);
978 if (element_index
< info
.size
) {
979 count
= std::min(info
.size
- element_index
, count
);
980 if (info
.IsSampler() && count
> 0) {
981 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
982 if (value
[ii
] < 0 || value
[ii
] >= num_texture_units
) {
986 std::copy(value
, value
+ count
,
987 info
.texture_units
.begin() + element_index
);
995 void Program::GetProgramiv(GLenum pname
, GLint
* params
) {
997 case GL_ACTIVE_ATTRIBUTES
:
998 *params
= attrib_infos_
.size();
1000 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
:
1001 // Notice +1 to accomodate NULL terminator.
1002 *params
= max_attrib_name_length_
+ 1;
1004 case GL_ACTIVE_UNIFORMS
:
1005 *params
= num_uniforms_
;
1007 case GL_ACTIVE_UNIFORM_MAX_LENGTH
:
1008 // Notice +1 to accomodate NULL terminator.
1009 *params
= max_uniform_name_length_
+ 1;
1011 case GL_LINK_STATUS
:
1012 *params
= link_status_
;
1014 case GL_INFO_LOG_LENGTH
:
1015 // Notice +1 to accomodate NULL terminator.
1016 *params
= log_info_
.get() ? (log_info_
->size() + 1) : 0;
1018 case GL_DELETE_STATUS
:
1021 case GL_VALIDATE_STATUS
:
1025 glGetProgramiv(service_id_
, pname
, params
);
1029 glGetProgramiv(service_id_
, pname
, params
);
1034 bool Program::AttachShader(
1035 ShaderManager
* shader_manager
,
1037 DCHECK(shader_manager
);
1039 int index
= ShaderTypeToIndex(shader
->shader_type());
1040 if (attached_shaders_
[index
].get() != NULL
) {
1043 attached_shaders_
[index
] = scoped_refptr
<Shader
>(shader
);
1044 shader_manager
->UseShader(shader
);
1048 bool Program::DetachShader(
1049 ShaderManager
* shader_manager
,
1051 DCHECK(shader_manager
);
1053 if (attached_shaders_
[ShaderTypeToIndex(shader
->shader_type())].get() !=
1057 attached_shaders_
[ShaderTypeToIndex(shader
->shader_type())] = NULL
;
1058 shader_manager
->UnuseShader(shader
);
1062 void Program::DetachShaders(ShaderManager
* shader_manager
) {
1063 DCHECK(shader_manager
);
1064 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1065 if (attached_shaders_
[ii
].get()) {
1066 DetachShader(shader_manager
, attached_shaders_
[ii
].get());
1071 void Program::CompileAttachedShaders() {
1072 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1073 Shader
* shader
= attached_shaders_
[ii
].get();
1075 shader
->DoCompile();
1080 bool Program::AttachedShadersExist() const {
1081 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1082 if (!attached_shaders_
[ii
].get())
1088 bool Program::CanLink() const {
1089 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1090 if (!attached_shaders_
[ii
].get() || !attached_shaders_
[ii
]->valid()) {
1097 bool Program::DetectShaderVersionMismatch() const {
1098 int version
= Shader::kUndefinedShaderVersion
;
1099 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1100 Shader
* shader
= attached_shaders_
[ii
].get();
1102 if (version
!= Shader::kUndefinedShaderVersion
&&
1103 shader
->shader_version() != version
) {
1106 version
= shader
->shader_version();
1107 DCHECK(version
!= Shader::kUndefinedShaderVersion
);
1113 bool Program::DetectAttribLocationBindingConflicts() const {
1114 std::set
<GLint
> location_binding_used
;
1115 for (LocationMap::const_iterator it
= bind_attrib_location_map_
.begin();
1116 it
!= bind_attrib_location_map_
.end(); ++it
) {
1117 // Find out if an attribute is statically used in this program's shaders.
1118 const sh::Attribute
* attrib
= NULL
;
1119 const std::string
* mapped_name
= GetAttribMappedName(it
->first
);
1122 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1123 if (!attached_shaders_
[ii
].get() || !attached_shaders_
[ii
]->valid())
1125 attrib
= attached_shaders_
[ii
]->GetAttribInfo(*mapped_name
);
1127 if (attrib
->staticUse
)
1134 size_t num_of_locations
= 1;
1135 switch (attrib
->type
) {
1137 num_of_locations
= 2;
1140 num_of_locations
= 3;
1143 num_of_locations
= 4;
1148 for (size_t ii
= 0; ii
< num_of_locations
; ++ii
) {
1149 GLint loc
= it
->second
+ ii
;
1150 std::pair
<std::set
<GLint
>::iterator
, bool> result
=
1151 location_binding_used
.insert(loc
);
1160 bool Program::DetectUniformsMismatch(std::string
* conflicting_name
) const {
1161 typedef std::map
<std::string
, const sh::Uniform
*> UniformPointerMap
;
1162 UniformPointerMap uniform_pointer_map
;
1163 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1164 const UniformMap
& shader_uniforms
= attached_shaders_
[ii
]->uniform_map();
1165 for (UniformMap::const_iterator iter
= shader_uniforms
.begin();
1166 iter
!= shader_uniforms
.end(); ++iter
) {
1167 const std::string
& name
= iter
->first
;
1168 UniformPointerMap::iterator hit
= uniform_pointer_map
.find(name
);
1169 if (hit
== uniform_pointer_map
.end()) {
1170 uniform_pointer_map
[name
] = &(iter
->second
);
1172 // If a uniform is in the map, i.e., it has already been declared by
1173 // another shader, then the type, precision, etc. must match.
1174 if (hit
->second
->isSameUniformAtLinkTime(iter
->second
))
1176 *conflicting_name
= name
;
1184 bool Program::DetectVaryingsMismatch(std::string
* conflicting_name
) const {
1185 DCHECK(attached_shaders_
[0].get() &&
1186 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1187 attached_shaders_
[1].get() &&
1188 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1189 const VaryingMap
* vertex_varyings
= &(attached_shaders_
[0]->varying_map());
1190 const VaryingMap
* fragment_varyings
= &(attached_shaders_
[1]->varying_map());
1192 int shader_version
= attached_shaders_
[0]->shader_version();
1194 for (VaryingMap::const_iterator iter
= fragment_varyings
->begin();
1195 iter
!= fragment_varyings
->end(); ++iter
) {
1196 const std::string
& name
= iter
->first
;
1197 if (IsBuiltInFragmentVarying(name
))
1200 VaryingMap::const_iterator hit
= vertex_varyings
->find(name
);
1201 if (hit
== vertex_varyings
->end()) {
1202 if (iter
->second
.staticUse
) {
1203 *conflicting_name
= name
;
1209 if (!hit
->second
.isSameVaryingAtLinkTime(iter
->second
, shader_version
)) {
1210 *conflicting_name
= name
;
1218 bool Program::DetectBuiltInInvariantConflicts() const {
1219 DCHECK(attached_shaders_
[0].get() &&
1220 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1221 attached_shaders_
[1].get() &&
1222 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1223 const VaryingMap
& vertex_varyings
= attached_shaders_
[0]->varying_map();
1224 const VaryingMap
& fragment_varyings
= attached_shaders_
[1]->varying_map();
1226 bool gl_position_invariant
= IsBuiltInInvariant(
1227 vertex_varyings
, "gl_Position");
1228 bool gl_point_size_invariant
= IsBuiltInInvariant(
1229 vertex_varyings
, "gl_PointSize");
1231 bool gl_frag_coord_invariant
= IsBuiltInInvariant(
1232 fragment_varyings
, "gl_FragCoord");
1233 bool gl_point_coord_invariant
= IsBuiltInInvariant(
1234 fragment_varyings
, "gl_PointCoord");
1236 return ((gl_frag_coord_invariant
&& !gl_position_invariant
) ||
1237 (gl_point_coord_invariant
&& !gl_point_size_invariant
));
1240 bool Program::DetectGlobalNameConflicts(std::string
* conflicting_name
) const {
1241 DCHECK(attached_shaders_
[0].get() &&
1242 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1243 attached_shaders_
[1].get() &&
1244 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1245 const UniformMap
* uniforms
[2];
1246 uniforms
[0] = &(attached_shaders_
[0]->uniform_map());
1247 uniforms
[1] = &(attached_shaders_
[1]->uniform_map());
1248 const AttributeMap
* attribs
=
1249 &(attached_shaders_
[0]->attrib_map());
1251 for (AttributeMap::const_iterator iter
= attribs
->begin();
1252 iter
!= attribs
->end(); ++iter
) {
1253 for (int ii
= 0; ii
< 2; ++ii
) {
1254 if (uniforms
[ii
]->find(iter
->first
) != uniforms
[ii
]->end()) {
1255 *conflicting_name
= iter
->first
;
1263 bool Program::CheckVaryingsPacking(
1264 Program::VaryingsPackingOption option
) const {
1265 DCHECK(attached_shaders_
[0].get() &&
1266 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1267 attached_shaders_
[1].get() &&
1268 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1269 const VaryingMap
* vertex_varyings
= &(attached_shaders_
[0]->varying_map());
1270 const VaryingMap
* fragment_varyings
= &(attached_shaders_
[1]->varying_map());
1272 std::map
<std::string
, ShVariableInfo
> combined_map
;
1274 for (VaryingMap::const_iterator iter
= fragment_varyings
->begin();
1275 iter
!= fragment_varyings
->end(); ++iter
) {
1276 if (!iter
->second
.staticUse
&& option
== kCountOnlyStaticallyUsed
)
1278 if (!IsBuiltInFragmentVarying(iter
->first
)) {
1279 VaryingMap::const_iterator vertex_iter
=
1280 vertex_varyings
->find(iter
->first
);
1281 if (vertex_iter
== vertex_varyings
->end() ||
1282 (!vertex_iter
->second
.staticUse
&&
1283 option
== kCountOnlyStaticallyUsed
))
1288 var
.type
= static_cast<sh::GLenum
>(iter
->second
.type
);
1289 var
.size
= std::max(1u, iter
->second
.arraySize
);
1290 combined_map
[iter
->first
] = var
;
1293 if (combined_map
.size() == 0)
1295 scoped_ptr
<ShVariableInfo
[]> variables(
1296 new ShVariableInfo
[combined_map
.size()]);
1298 for (std::map
<std::string
, ShVariableInfo
>::const_iterator iter
=
1299 combined_map
.begin();
1300 iter
!= combined_map
.end(); ++iter
) {
1301 variables
[index
].type
= iter
->second
.type
;
1302 variables
[index
].size
= iter
->second
.size
;
1305 return ShCheckVariablesWithinPackingLimits(
1306 static_cast<int>(manager_
->max_varying_vectors()),
1308 combined_map
.size());
1311 void Program::GetProgramInfo(
1312 ProgramManager
* manager
, CommonDecoder::Bucket
* bucket
) const {
1313 // NOTE: It seems to me the math in here does not need check for overflow
1314 // because the data being calucated from has various small limits. The max
1315 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1316 // of an identifier is 256 characters.
1317 uint32 num_locations
= 0;
1318 uint32 total_string_size
= 0;
1320 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
1321 const VertexAttrib
& info
= attrib_infos_
[ii
];
1323 total_string_size
+= info
.name
.size();
1326 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
1327 const UniformInfo
& info
= uniform_infos_
[ii
];
1328 if (info
.IsValid()) {
1329 num_locations
+= info
.element_locations
.size();
1330 total_string_size
+= info
.name
.size();
1334 uint32 num_inputs
= attrib_infos_
.size() + num_uniforms_
;
1335 uint32 input_size
= num_inputs
* sizeof(ProgramInput
);
1336 uint32 location_size
= num_locations
* sizeof(int32
);
1337 uint32 size
= sizeof(ProgramInfoHeader
) +
1338 input_size
+ location_size
+ total_string_size
;
1340 bucket
->SetSize(size
);
1341 ProgramInfoHeader
* header
= bucket
->GetDataAs
<ProgramInfoHeader
*>(0, size
);
1342 ProgramInput
* inputs
= bucket
->GetDataAs
<ProgramInput
*>(
1343 sizeof(ProgramInfoHeader
), input_size
);
1344 int32
* locations
= bucket
->GetDataAs
<int32
*>(
1345 sizeof(ProgramInfoHeader
) + input_size
, location_size
);
1346 char* strings
= bucket
->GetDataAs
<char*>(
1347 sizeof(ProgramInfoHeader
) + input_size
+ location_size
,
1354 header
->link_status
= link_status_
;
1355 header
->num_attribs
= attrib_infos_
.size();
1356 header
->num_uniforms
= num_uniforms_
;
1358 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
1359 const VertexAttrib
& info
= attrib_infos_
[ii
];
1360 inputs
->size
= info
.size
;
1361 inputs
->type
= info
.type
;
1362 inputs
->location_offset
= ComputeOffset(header
, locations
);
1363 inputs
->name_offset
= ComputeOffset(header
, strings
);
1364 inputs
->name_length
= info
.name
.size();
1365 *locations
++ = info
.location
;
1366 memcpy(strings
, info
.name
.c_str(), info
.name
.size());
1367 strings
+= info
.name
.size();
1371 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
1372 const UniformInfo
& info
= uniform_infos_
[ii
];
1373 if (info
.IsValid()) {
1374 inputs
->size
= info
.size
;
1375 inputs
->type
= info
.type
;
1376 inputs
->location_offset
= ComputeOffset(header
, locations
);
1377 inputs
->name_offset
= ComputeOffset(header
, strings
);
1378 inputs
->name_length
= info
.name
.size();
1379 DCHECK(static_cast<size_t>(info
.size
) == info
.element_locations
.size());
1380 for (size_t jj
= 0; jj
< info
.element_locations
.size(); ++jj
) {
1381 if (info
.element_locations
[jj
] == -1)
1384 *locations
++ = ProgramManager::MakeFakeLocation(ii
, jj
);
1386 memcpy(strings
, info
.name
.c_str(), info
.name
.size());
1387 strings
+= info
.name
.size();
1392 DCHECK_EQ(ComputeOffset(header
, strings
), size
);
1395 bool Program::GetUniformBlocks(CommonDecoder::Bucket
* bucket
) const {
1396 // The data is packed into the bucket in the following order
1398 // 2) N entries of block data (except for name and indices)
1399 // 3) name1, indices1, name2, indices2, ..., nameN, indicesN
1401 // We query all the data directly through GL calls, assuming they are
1402 // cheap through MANGLE.
1405 GLuint program
= service_id();
1407 uint32_t header_size
= sizeof(UniformBlocksHeader
);
1408 bucket
->SetSize(header_size
); // In case we fail.
1410 uint32_t num_uniform_blocks
= 0;
1411 GLint param
= GL_FALSE
;
1412 // We assume program is a valid program service id.
1413 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1414 if (param
== GL_TRUE
) {
1416 glGetProgramiv(program
, GL_ACTIVE_UNIFORM_BLOCKS
, ¶m
);
1417 num_uniform_blocks
= static_cast<uint32_t>(param
);
1419 if (num_uniform_blocks
== 0) {
1420 // Although spec allows an implementation to return uniform block info
1421 // even if a link fails, for consistency, we disallow that.
1425 std::vector
<UniformBlockInfo
> blocks(num_uniform_blocks
);
1426 base::CheckedNumeric
<uint32_t> size
= sizeof(UniformBlockInfo
);
1427 size
*= num_uniform_blocks
;
1428 uint32_t entry_size
= size
.ValueOrDefault(0);
1429 size
+= header_size
;
1430 std::vector
<std::string
> names(num_uniform_blocks
);
1431 GLint max_name_length
= 0;
1433 program
, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH
, &max_name_length
);
1434 std::vector
<GLchar
> buffer(max_name_length
);
1436 for (uint32_t ii
= 0; ii
< num_uniform_blocks
; ++ii
) {
1438 glGetActiveUniformBlockiv(program
, ii
, GL_UNIFORM_BLOCK_BINDING
, ¶m
);
1439 blocks
[ii
].binding
= static_cast<uint32_t>(param
);
1442 glGetActiveUniformBlockiv(program
, ii
, GL_UNIFORM_BLOCK_DATA_SIZE
, ¶m
);
1443 blocks
[ii
].data_size
= static_cast<uint32_t>(param
);
1445 blocks
[ii
].name_offset
= size
.ValueOrDefault(0);
1447 glGetActiveUniformBlockiv(
1448 program
, ii
, GL_UNIFORM_BLOCK_NAME_LENGTH
, ¶m
);
1449 DCHECK_GE(max_name_length
, param
);
1450 memset(&buffer
[0], 0, param
);
1452 glGetActiveUniformBlockName(
1453 program
, ii
, static_cast<GLsizei
>(param
), &length
, &buffer
[0]);
1454 DCHECK_EQ(param
, length
+ 1);
1455 names
[ii
] = std::string(&buffer
[0], length
);
1456 // TODO(zmo): optimize the name mapping lookup.
1457 const std::string
* original_name
= GetOriginalNameFromHashedName(names
[ii
]);
1459 names
[ii
] = *original_name
;
1460 blocks
[ii
].name_length
= names
[ii
].size() + 1;
1461 size
+= blocks
[ii
].name_length
;
1464 glGetActiveUniformBlockiv(
1465 program
, ii
, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS
, ¶m
);
1466 blocks
[ii
].active_uniforms
= static_cast<uint32_t>(param
);
1467 blocks
[ii
].active_uniform_offset
= size
.ValueOrDefault(0);
1468 base::CheckedNumeric
<uint32_t> indices_size
= blocks
[ii
].active_uniforms
;
1469 indices_size
*= sizeof(uint32_t);
1470 if (!indices_size
.IsValid())
1472 size
+= indices_size
.ValueOrDefault(0);
1475 glGetActiveUniformBlockiv(
1476 program
, ii
, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER
, ¶m
);
1477 blocks
[ii
].referenced_by_vertex_shader
= static_cast<uint32_t>(param
);
1480 glGetActiveUniformBlockiv(
1481 program
, ii
, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
, ¶m
);
1482 blocks
[ii
].referenced_by_fragment_shader
= static_cast<uint32_t>(param
);
1484 if (!size
.IsValid())
1486 uint32_t total_size
= size
.ValueOrDefault(0);
1487 DCHECK_LE(header_size
+ entry_size
, total_size
);
1488 uint32_t data_size
= total_size
- header_size
- entry_size
;
1490 bucket
->SetSize(total_size
);
1491 UniformBlocksHeader
* header
=
1492 bucket
->GetDataAs
<UniformBlocksHeader
*>(0, header_size
);
1493 UniformBlockInfo
* entries
= bucket
->GetDataAs
<UniformBlockInfo
*>(
1494 header_size
, entry_size
);
1495 char* data
= bucket
->GetDataAs
<char*>(header_size
+ entry_size
, data_size
);
1500 // Copy over data for the header and entries.
1501 header
->num_uniform_blocks
= num_uniform_blocks
;
1502 memcpy(entries
, &blocks
[0], entry_size
);
1504 std::vector
<GLint
> params
;
1505 for (uint32_t ii
= 0; ii
< num_uniform_blocks
; ++ii
) {
1506 // Get active uniform name.
1507 memcpy(data
, names
[ii
].c_str(), names
[ii
].length() + 1);
1508 data
+= names
[ii
].length() + 1;
1510 // Get active uniform indices.
1511 if (params
.size() < blocks
[ii
].active_uniforms
)
1512 params
.resize(blocks
[ii
].active_uniforms
);
1513 uint32_t num_bytes
= blocks
[ii
].active_uniforms
* sizeof(GLint
);
1514 memset(¶ms
[0], 0, num_bytes
);
1515 glGetActiveUniformBlockiv(
1516 program
, ii
, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
, ¶ms
[0]);
1517 uint32_t* indices
= reinterpret_cast<uint32_t*>(data
);
1518 for (uint32_t uu
= 0; uu
< blocks
[ii
].active_uniforms
; ++uu
) {
1519 indices
[uu
] = static_cast<uint32_t>(params
[uu
]);
1523 DCHECK_EQ(ComputeOffset(header
, data
), total_size
);
1527 bool Program::GetTransformFeedbackVaryings(
1528 CommonDecoder::Bucket
* bucket
) const {
1529 // The data is packed into the bucket in the following order
1531 // 2) N entries of varying data (except for name)
1532 // 3) name1, name2, ..., nameN
1534 // We query all the data directly through GL calls, assuming they are
1535 // cheap through MANGLE.
1538 GLuint program
= service_id();
1540 uint32_t header_size
= sizeof(TransformFeedbackVaryingsHeader
);
1541 bucket
->SetSize(header_size
); // In case we fail.
1543 uint32_t num_transform_feedback_varyings
= 0;
1544 GLint param
= GL_FALSE
;
1545 // We assume program is a valid program service id.
1546 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1547 if (param
== GL_TRUE
) {
1549 glGetProgramiv(program
, GL_TRANSFORM_FEEDBACK_VARYINGS
, ¶m
);
1550 num_transform_feedback_varyings
= static_cast<uint32_t>(param
);
1552 if (num_transform_feedback_varyings
== 0) {
1556 std::vector
<TransformFeedbackVaryingInfo
> varyings(
1557 num_transform_feedback_varyings
);
1558 base::CheckedNumeric
<uint32_t> size
= sizeof(TransformFeedbackVaryingInfo
);
1559 size
*= num_transform_feedback_varyings
;
1560 uint32_t entry_size
= size
.ValueOrDefault(0);
1561 size
+= header_size
;
1562 std::vector
<std::string
> names(num_transform_feedback_varyings
);
1563 GLint max_name_length
= 0;
1565 program
, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH
, &max_name_length
);
1566 if (max_name_length
< 1)
1567 max_name_length
= 1;
1568 std::vector
<char> buffer(max_name_length
);
1569 for (uint32_t ii
= 0; ii
< num_transform_feedback_varyings
; ++ii
) {
1570 GLsizei var_size
= 0;
1571 GLsizei var_name_length
= 0;
1572 GLenum var_type
= 0;
1573 glGetTransformFeedbackVarying(
1574 program
, ii
, max_name_length
,
1575 &var_name_length
, &var_size
, &var_type
, &buffer
[0]);
1576 varyings
[ii
].size
= static_cast<uint32_t>(var_size
);
1577 varyings
[ii
].type
= static_cast<uint32_t>(var_type
);
1578 varyings
[ii
].name_offset
= static_cast<uint32_t>(size
.ValueOrDefault(0));
1579 DCHECK_GT(max_name_length
, var_name_length
);
1580 names
[ii
] = std::string(&buffer
[0], var_name_length
);
1581 // TODO(zmo): optimize the name mapping lookup.
1582 const std::string
* original_name
= GetOriginalNameFromHashedName(names
[ii
]);
1584 names
[ii
] = *original_name
;
1585 varyings
[ii
].name_length
= names
[ii
].size() + 1;
1586 size
+= names
[ii
].size();
1589 if (!size
.IsValid())
1591 uint32_t total_size
= size
.ValueOrDefault(0);
1592 DCHECK_LE(header_size
+ entry_size
, total_size
);
1593 uint32_t data_size
= total_size
- header_size
- entry_size
;
1595 bucket
->SetSize(total_size
);
1596 TransformFeedbackVaryingsHeader
* header
=
1597 bucket
->GetDataAs
<TransformFeedbackVaryingsHeader
*>(0, header_size
);
1598 TransformFeedbackVaryingInfo
* entries
=
1599 bucket
->GetDataAs
<TransformFeedbackVaryingInfo
*>(header_size
, entry_size
);
1600 char* data
= bucket
->GetDataAs
<char*>(header_size
+ entry_size
, data_size
);
1605 // Copy over data for the header and entries.
1606 header
->num_transform_feedback_varyings
= num_transform_feedback_varyings
;
1607 memcpy(entries
, &varyings
[0], entry_size
);
1609 for (uint32_t ii
= 0; ii
< num_transform_feedback_varyings
; ++ii
) {
1610 memcpy(data
, names
[ii
].c_str(), names
[ii
].length() + 1);
1611 data
+= names
[ii
].length() + 1;
1613 DCHECK_EQ(ComputeOffset(header
, data
), total_size
);
1617 bool Program::GetUniformsES3(CommonDecoder::Bucket
* bucket
) const {
1618 // The data is packed into the bucket in the following order
1620 // 2) N entries of UniformES3Info
1622 // We query all the data directly through GL calls, assuming they are
1623 // cheap through MANGLE.
1626 GLuint program
= service_id();
1628 uint32_t header_size
= sizeof(UniformsES3Header
);
1629 bucket
->SetSize(header_size
); // In case we fail.
1632 GLint param
= GL_FALSE
;
1633 // We assume program is a valid program service id.
1634 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1635 if (param
== GL_TRUE
) {
1637 glGetProgramiv(program
, GL_ACTIVE_UNIFORMS
, &count
);
1643 base::CheckedNumeric
<uint32_t> size
= sizeof(UniformES3Info
);
1645 uint32_t entry_size
= size
.ValueOrDefault(0);
1646 size
+= header_size
;
1647 if (!size
.IsValid())
1649 uint32_t total_size
= size
.ValueOrDefault(0);
1650 bucket
->SetSize(total_size
);
1651 UniformsES3Header
* header
=
1652 bucket
->GetDataAs
<UniformsES3Header
*>(0, header_size
);
1654 header
->num_uniforms
= static_cast<uint32_t>(count
);
1656 // Instead of GetDataAs<UniformES3Info*>, we do GetDataAs<int32_t>. This is
1657 // because struct UniformES3Info is defined as five int32_t.
1658 // By doing this, we can fill the structs through loops.
1660 bucket
->GetDataAs
<int32_t*>(header_size
, entry_size
);
1662 const size_t kStride
= sizeof(UniformES3Info
) / sizeof(int32_t);
1664 const GLenum kPname
[] = {
1665 GL_UNIFORM_BLOCK_INDEX
,
1667 GL_UNIFORM_ARRAY_STRIDE
,
1668 GL_UNIFORM_MATRIX_STRIDE
,
1669 GL_UNIFORM_IS_ROW_MAJOR
,
1671 const GLint kDefaultValue
[] = { -1, -1, -1, -1, 0 };
1672 const size_t kNumPnames
= arraysize(kPname
);
1673 std::vector
<GLuint
> indices(count
);
1674 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1677 std::vector
<GLint
> params(count
);
1678 for (size_t pname_index
= 0; pname_index
< kNumPnames
; ++pname_index
) {
1679 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1680 params
[ii
] = kDefaultValue
[pname_index
];
1682 glGetActiveUniformsiv(
1683 program
, count
, &indices
[0], kPname
[pname_index
], ¶ms
[0]);
1684 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1685 entries
[kStride
* ii
+ pname_index
] = params
[ii
];
1691 void Program::TransformFeedbackVaryings(GLsizei count
,
1692 const char* const* varyings
,
1693 GLenum buffer_mode
) {
1694 transform_feedback_varyings_
.clear();
1695 for (GLsizei i
= 0; i
< count
; ++i
) {
1696 transform_feedback_varyings_
.push_back(std::string(varyings
[i
]));
1698 transform_feedback_buffer_mode_
= buffer_mode
;
1701 Program::~Program() {
1703 if (manager_
->have_context_
) {
1704 glDeleteProgram(service_id());
1706 manager_
->StopTracking(this);
1712 ProgramManager::ProgramManager(ProgramCache
* program_cache
,
1713 uint32 max_varying_vectors
)
1714 : program_count_(0),
1715 have_context_(true),
1716 program_cache_(program_cache
),
1717 max_varying_vectors_(max_varying_vectors
) { }
1719 ProgramManager::~ProgramManager() {
1720 DCHECK(programs_
.empty());
1723 void ProgramManager::Destroy(bool have_context
) {
1724 have_context_
= have_context
;
1728 void ProgramManager::StartTracking(Program
* /* program */) {
1732 void ProgramManager::StopTracking(Program
* /* program */) {
1736 Program
* ProgramManager::CreateProgram(
1737 GLuint client_id
, GLuint service_id
) {
1738 std::pair
<ProgramMap::iterator
, bool> result
=
1740 std::make_pair(client_id
,
1741 scoped_refptr
<Program
>(
1742 new Program(this, service_id
))));
1743 DCHECK(result
.second
);
1744 return result
.first
->second
.get();
1747 Program
* ProgramManager::GetProgram(GLuint client_id
) {
1748 ProgramMap::iterator it
= programs_
.find(client_id
);
1749 return it
!= programs_
.end() ? it
->second
.get() : NULL
;
1752 bool ProgramManager::GetClientId(GLuint service_id
, GLuint
* client_id
) const {
1753 // This doesn't need to be fast. It's only used during slow queries.
1754 for (ProgramMap::const_iterator it
= programs_
.begin();
1755 it
!= programs_
.end(); ++it
) {
1756 if (it
->second
->service_id() == service_id
) {
1757 *client_id
= it
->first
;
1764 ProgramCache
* ProgramManager::program_cache() const {
1765 return program_cache_
;
1768 bool ProgramManager::IsOwned(Program
* program
) {
1769 for (ProgramMap::iterator it
= programs_
.begin();
1770 it
!= programs_
.end(); ++it
) {
1771 if (it
->second
.get() == program
) {
1778 void ProgramManager::RemoveProgramInfoIfUnused(
1779 ShaderManager
* shader_manager
, Program
* program
) {
1780 DCHECK(shader_manager
);
1782 DCHECK(IsOwned(program
));
1783 if (program
->IsDeleted() && !program
->InUse()) {
1784 program
->DetachShaders(shader_manager
);
1785 for (ProgramMap::iterator it
= programs_
.begin();
1786 it
!= programs_
.end(); ++it
) {
1787 if (it
->second
.get() == program
) {
1788 programs_
.erase(it
);
1796 void ProgramManager::MarkAsDeleted(
1797 ShaderManager
* shader_manager
,
1799 DCHECK(shader_manager
);
1801 DCHECK(IsOwned(program
));
1802 program
->MarkAsDeleted();
1803 RemoveProgramInfoIfUnused(shader_manager
, program
);
1806 void ProgramManager::UseProgram(Program
* program
) {
1808 DCHECK(IsOwned(program
));
1809 program
->IncUseCount();
1812 void ProgramManager::UnuseProgram(
1813 ShaderManager
* shader_manager
,
1815 DCHECK(shader_manager
);
1817 DCHECK(IsOwned(program
));
1818 program
->DecUseCount();
1819 RemoveProgramInfoIfUnused(shader_manager
, program
);
1822 void ProgramManager::ClearUniforms(Program
* program
) {
1824 program
->ClearUniforms(&zero_
);
1827 int32
ProgramManager::MakeFakeLocation(int32 index
, int32 element
) {
1828 return index
+ element
* 0x10000;
1831 } // namespace gles2