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