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