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
;
284 uint32 unit_size
= GLES2Util::GetGLDataTypeSizeForUniforms(
286 uint32 size_needed
= size
* unit_size
;
287 if (size_needed
> zero_buffer
->size()) {
288 zero_buffer
->resize(size_needed
, 0u);
290 const void* zero
= &(*zero_buffer
)[0];
291 switch (uniform_info
.type
) {
293 glUniform1fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
296 glUniform2fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
299 glUniform3fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
302 glUniform4fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
307 case GL_SAMPLER_CUBE
:
308 case GL_SAMPLER_EXTERNAL_OES
:
309 case GL_SAMPLER_3D_OES
:
310 case GL_SAMPLER_2D_RECT_ARB
:
311 glUniform1iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
315 glUniform2iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
319 glUniform3iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
323 glUniform4iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
327 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
331 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
335 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
347 UniformData() : size(-1), type(GL_NONE
), location(0), added(false) {
349 std::string queried_name
;
350 std::string corrected_name
;
351 std::string original_name
;
358 struct UniformDataComparer
{
359 bool operator()(const UniformData
& lhs
, const UniformData
& rhs
) const {
360 return lhs
.queried_name
< rhs
.queried_name
;
364 } // anonymous namespace
366 void Program::Update() {
370 uniforms_cleared_
= false;
371 GLint num_attribs
= 0;
373 GLint max_location
= -1;
374 glGetProgramiv(service_id_
, GL_ACTIVE_ATTRIBUTES
, &num_attribs
);
375 glGetProgramiv(service_id_
, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
, &max_len
);
376 // TODO(gman): Should we check for error?
377 scoped_ptr
<char[]> name_buffer(new char[max_len
]);
378 for (GLint ii
= 0; ii
< num_attribs
; ++ii
) {
383 service_id_
, ii
, max_len
, &length
, &size
, &type
, name_buffer
.get());
384 DCHECK(max_len
== 0 || length
< max_len
);
385 DCHECK(length
== 0 || name_buffer
[length
] == '\0');
386 if (!ProgramManager::IsInvalidPrefix(name_buffer
.get(), length
)) {
387 std::string original_name
;
388 GetVertexAttribData(name_buffer
.get(), &original_name
, &type
);
389 // TODO(gman): Should we check for error?
390 GLint location
= glGetAttribLocation(service_id_
, name_buffer
.get());
391 if (location
> max_location
) {
392 max_location
= location
;
394 attrib_infos_
.push_back(
395 VertexAttrib(1, type
, original_name
, location
));
396 max_attrib_name_length_
= std::max(
397 max_attrib_name_length_
, static_cast<GLsizei
>(original_name
.size()));
401 // Create attrib location to index map.
402 attrib_location_to_index_map_
.resize(max_location
+ 1);
403 for (GLint ii
= 0; ii
<= max_location
; ++ii
) {
404 attrib_location_to_index_map_
[ii
] = -1;
406 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
407 const VertexAttrib
& info
= attrib_infos_
[ii
];
408 attrib_location_to_index_map_
[info
.location
] = ii
;
412 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
413 switches::kEnableGPUServiceLoggingGPU
)) {
414 DVLOG(1) << "----: attribs for service_id: " << service_id();
415 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
416 const VertexAttrib
& info
= attrib_infos_
[ii
];
417 DVLOG(1) << ii
<< ": loc = " << info
.location
418 << ", size = " << info
.size
419 << ", type = " << GLES2Util::GetStringEnum(info
.type
)
420 << ", name = " << info
.name
;
426 GLint num_uniforms
= 0;
427 glGetProgramiv(service_id_
, GL_ACTIVE_UNIFORMS
, &num_uniforms
);
428 glGetProgramiv(service_id_
, GL_ACTIVE_UNIFORM_MAX_LENGTH
, &max_len
);
429 name_buffer
.reset(new char[max_len
]);
431 // Reads all the names.
432 std::vector
<UniformData
> uniform_data
;
433 for (GLint ii
= 0; ii
< num_uniforms
; ++ii
) {
437 service_id_
, ii
, max_len
, &length
,
438 &data
.size
, &data
.type
, name_buffer
.get());
439 DCHECK(max_len
== 0 || length
< max_len
);
440 DCHECK(length
== 0 || name_buffer
[length
] == '\0');
441 if (!ProgramManager::IsInvalidPrefix(name_buffer
.get(), length
)) {
442 data
.queried_name
= std::string(name_buffer
.get());
443 GetCorrectedUniformData(
445 &data
.corrected_name
, &data
.original_name
, &data
.size
, &data
.type
);
446 uniform_data
.push_back(data
);
450 // NOTE: We don't care if 2 uniforms are bound to the same location.
451 // One of them will take preference. The spec allows this, same as
452 // BindAttribLocation.
454 // The reason we don't check is if we were to fail we'd have to
455 // restore the previous program but since we've already linked successfully
456 // at this point the previous program is gone.
458 // Assigns the uniforms with bindings.
459 size_t next_available_index
= 0;
460 for (size_t ii
= 0; ii
< uniform_data
.size(); ++ii
) {
461 UniformData
& data
= uniform_data
[ii
];
462 data
.location
= glGetUniformLocation(
463 service_id_
, data
.queried_name
.c_str());
465 std::string short_name
;
466 int element_index
= 0;
467 bool good
= GetUniformNameSansElement(data
.queried_name
, &element_index
,
470 LocationMap::const_iterator it
= bind_uniform_location_map_
.find(
472 if (it
!= bind_uniform_location_map_
.end()) {
473 data
.added
= AddUniformInfo(
474 data
.size
, data
.type
, data
.location
, it
->second
, data
.corrected_name
,
475 data
.original_name
, &next_available_index
);
479 // Assigns the uniforms that were not bound.
480 for (size_t ii
= 0; ii
< uniform_data
.size(); ++ii
) {
481 const UniformData
& data
= uniform_data
[ii
];
484 data
.size
, data
.type
, data
.location
, -1, data
.corrected_name
,
485 data
.original_name
, &next_available_index
);
490 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
491 switches::kEnableGPUServiceLoggingGPU
)) {
492 DVLOG(1) << "----: uniforms for service_id: " << service_id();
493 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
494 const UniformInfo
& info
= uniform_infos_
[ii
];
495 if (info
.IsValid()) {
496 DVLOG(1) << ii
<< ": loc = " << info
.element_locations
[0]
497 << ", size = " << info
.size
498 << ", type = " << GLES2Util::GetStringEnum(info
.type
)
499 << ", name = " << info
.name
;
508 void Program::ExecuteBindAttribLocationCalls() {
509 for (LocationMap::const_iterator it
= bind_attrib_location_map_
.begin();
510 it
!= bind_attrib_location_map_
.end(); ++it
) {
511 const std::string
* mapped_name
= GetAttribMappedName(it
->first
);
513 glBindAttribLocation(service_id_
, it
->second
, mapped_name
->c_str());
517 bool Program::Link(ShaderManager
* manager
,
518 Program::VaryingsPackingOption varyings_packing_option
,
519 const ShaderCacheCallback
& shader_callback
) {
522 if (!AttachedShadersExist()) {
523 set_log_info("missing shaders");
527 TimeTicks before_time
= TimeTicks::Now();
529 ProgramCache
* cache
= manager_
->program_cache_
;
531 DCHECK(!attached_shaders_
[0]->last_compiled_source().empty() &&
532 !attached_shaders_
[1]->last_compiled_source().empty());
533 ProgramCache::LinkedProgramStatus status
= cache
->GetLinkedProgramStatus(
534 attached_shaders_
[0]->last_compiled_signature(),
535 attached_shaders_
[1]->last_compiled_signature(),
536 &bind_attrib_location_map_
,
537 transform_feedback_varyings_
,
538 transform_feedback_buffer_mode_
);
540 if (status
== ProgramCache::LINK_SUCCEEDED
) {
541 ProgramCache::ProgramLoadResult success
=
542 cache
->LoadLinkedProgram(service_id(),
543 attached_shaders_
[0].get(),
544 attached_shaders_
[1].get(),
545 &bind_attrib_location_map_
,
546 transform_feedback_varyings_
,
547 transform_feedback_buffer_mode_
,
549 link
= success
!= ProgramCache::PROGRAM_LOAD_SUCCESS
;
550 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link
);
555 CompileAttachedShaders();
558 set_log_info("invalid shaders");
561 if (DetectAttribLocationBindingConflicts()) {
562 set_log_info("glBindAttribLocation() conflicts");
565 std::string conflicting_name
;
566 if (DetectUniformsMismatch(&conflicting_name
)) {
567 std::string info_log
= "Uniforms with the same name but different "
568 "type/precision: " + conflicting_name
;
569 set_log_info(ProcessLogInfo(info_log
).c_str());
572 if (DetectVaryingsMismatch(&conflicting_name
)) {
573 std::string info_log
= "Varyings with the same name but different type, "
574 "or statically used varyings in fragment shader "
575 "are not declared in vertex shader: " +
577 set_log_info(ProcessLogInfo(info_log
).c_str());
580 if (DetectBuiltInInvariantConflicts()) {
581 set_log_info("Invariant settings for certain built-in varyings "
585 if (DetectGlobalNameConflicts(&conflicting_name
)) {
586 std::string info_log
= "Name conflicts between an uniform and an "
587 "attribute: " + conflicting_name
;
588 set_log_info(ProcessLogInfo(info_log
).c_str());
591 if (!CheckVaryingsPacking(varyings_packing_option
)) {
592 set_log_info("Varyings over maximum register limit");
596 ExecuteBindAttribLocationCalls();
597 before_time
= TimeTicks::Now();
598 if (cache
&& gfx::g_driver_gl
.ext
.b_GL_ARB_get_program_binary
) {
599 glProgramParameteri(service_id(),
600 PROGRAM_BINARY_RETRIEVABLE_HINT
,
603 glLinkProgram(service_id());
607 glGetProgramiv(service_id(), GL_LINK_STATUS
, &success
);
608 if (success
== GL_TRUE
) {
612 cache
->SaveLinkedProgram(service_id(),
613 attached_shaders_
[0].get(),
614 attached_shaders_
[1].get(),
615 &bind_attrib_location_map_
,
616 transform_feedback_varyings_
,
617 transform_feedback_buffer_mode_
,
620 UMA_HISTOGRAM_CUSTOM_COUNTS(
621 "GPU.ProgramCache.BinaryCacheMissTime",
622 static_cast<base::HistogramBase::Sample
>(
623 (TimeTicks::Now() - before_time
).InMicroseconds()),
625 static_cast<base::HistogramBase::Sample
>(
626 TimeDelta::FromSeconds(10).InMicroseconds()),
629 UMA_HISTOGRAM_CUSTOM_COUNTS(
630 "GPU.ProgramCache.BinaryCacheHitTime",
631 static_cast<base::HistogramBase::Sample
>(
632 (TimeTicks::Now() - before_time
).InMicroseconds()),
634 static_cast<base::HistogramBase::Sample
>(
635 TimeDelta::FromSeconds(1).InMicroseconds()),
641 return success
== GL_TRUE
;
644 void Program::Validate() {
646 set_log_info("program not linked");
649 glValidateProgram(service_id());
653 GLint
Program::GetUniformFakeLocation(
654 const std::string
& name
) const {
655 bool getting_array_location
= false;
656 size_t open_pos
= std::string::npos
;
658 if (!GLES2Util::ParseUniformName(
659 name
, &open_pos
, &index
, &getting_array_location
)) {
662 for (GLuint ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
663 const UniformInfo
& info
= uniform_infos_
[ii
];
664 if (!info
.IsValid()) {
667 if (info
.name
== name
||
669 info
.name
.compare(0, info
.name
.size() - 3, name
) == 0)) {
670 return info
.fake_location_base
;
671 } else if (getting_array_location
&& info
.is_array
) {
672 // Look for an array specification.
673 size_t open_pos_2
= info
.name
.find_last_of('[');
674 if (open_pos_2
== open_pos
&&
675 name
.compare(0, open_pos
, info
.name
, 0, open_pos
) == 0) {
676 if (index
>= 0 && index
< info
.size
) {
677 DCHECK_GT(static_cast<int>(info
.element_locations
.size()), index
);
678 if (info
.element_locations
[index
] == -1)
680 return ProgramManager::MakeFakeLocation(
681 info
.fake_location_base
, index
);
689 GLint
Program::GetAttribLocation(
690 const std::string
& original_name
) const {
691 for (GLuint ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
692 const VertexAttrib
& info
= attrib_infos_
[ii
];
693 if (info
.name
== original_name
) {
694 return info
.location
;
700 const Program::UniformInfo
*
701 Program::GetUniformInfoByFakeLocation(
702 GLint fake_location
, GLint
* real_location
, GLint
* array_index
) const {
703 DCHECK(real_location
);
705 if (fake_location
< 0) {
709 GLint uniform_index
= GetUniformInfoIndexFromFakeLocation(fake_location
);
710 if (uniform_index
>= 0 &&
711 static_cast<size_t>(uniform_index
) < uniform_infos_
.size()) {
712 const UniformInfo
& uniform_info
= uniform_infos_
[uniform_index
];
713 if (!uniform_info
.IsValid()) {
716 GLint element_index
= GetArrayElementIndexFromFakeLocation(fake_location
);
717 if (element_index
< uniform_info
.size
) {
718 *real_location
= uniform_info
.element_locations
[element_index
];
719 *array_index
= element_index
;
720 return &uniform_info
;
726 const std::string
* Program::GetAttribMappedName(
727 const std::string
& original_name
) const {
728 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
729 Shader
* shader
= attached_shaders_
[ii
].get();
731 const std::string
* mapped_name
=
732 shader
->GetAttribMappedName(original_name
);
740 const std::string
* Program::GetOriginalNameFromHashedName(
741 const std::string
& hashed_name
) const {
742 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
743 Shader
* shader
= attached_shaders_
[ii
].get();
745 const std::string
* original_name
=
746 shader
->GetOriginalNameFromHashedName(hashed_name
);
748 return original_name
;
754 bool Program::SetUniformLocationBinding(
755 const std::string
& name
, GLint location
) {
756 std::string short_name
;
757 int element_index
= 0;
758 if (!GetUniformNameSansElement(name
, &element_index
, &short_name
) ||
759 element_index
!= 0) {
763 bind_uniform_location_map_
[short_name
] = location
;
767 // Note: This is only valid to call right after a program has been linked
769 void Program::GetCorrectedUniformData(
770 const std::string
& name
,
771 std::string
* corrected_name
, std::string
* original_name
,
772 GLsizei
* size
, GLenum
* type
) const {
773 DCHECK(corrected_name
&& original_name
&& size
&& type
);
774 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
775 Shader
* shader
= attached_shaders_
[ii
].get();
778 const sh::ShaderVariable
* info
= NULL
;
779 const sh::Uniform
* uniform
= shader
->GetUniformInfo(name
);
782 found
= uniform
->findInfoByMappedName(name
, &info
, original_name
);
784 const std::string
kArraySpec("[0]");
785 if (info
->arraySize
> 0 && !EndsWith(name
, kArraySpec
, true)) {
786 *corrected_name
= name
+ kArraySpec
;
787 *original_name
+= kArraySpec
;
789 *corrected_name
= name
;
792 *size
= std::max(1u, info
->arraySize
);
796 // TODO(zmo): this path should never be reached unless there is a serious
797 // bug in the driver or in ANGLE translator.
798 *corrected_name
= name
;
799 *original_name
= name
;
802 void Program::GetVertexAttribData(
803 const std::string
& name
, std::string
* original_name
, GLenum
* type
) const {
804 DCHECK(original_name
);
806 Shader
* shader
= attached_shaders_
[ShaderTypeToIndex(GL_VERTEX_SHADER
)].get();
808 // Vertex attributes can not be arrays or structs (GLSL ES 3.00.4, section
809 // 4.3.4, "Input Variables"), so the top level sh::Attribute returns the
810 // information we need.
811 const sh::Attribute
* info
= shader
->GetAttribInfo(name
);
813 *original_name
= info
->name
;
818 // TODO(zmo): this path should never be reached unless there is a serious
819 // bug in the driver or in ANGLE translator.
820 *original_name
= name
;
823 bool Program::AddUniformInfo(
824 GLsizei size
, GLenum type
, GLint location
, GLint fake_base_location
,
825 const std::string
& name
, const std::string
& original_name
,
826 size_t* next_available_index
) {
827 DCHECK(next_available_index
);
828 const char* kArraySpec
= "[0]";
829 size_t uniform_index
=
830 fake_base_location
>= 0 ? fake_base_location
: *next_available_index
;
831 if (uniform_infos_
.size() < uniform_index
+ 1) {
832 uniform_infos_
.resize(uniform_index
+ 1);
835 // return if this location is already in use.
836 if (uniform_infos_
[uniform_index
].IsValid()) {
837 DCHECK_GE(fake_base_location
, 0);
841 uniform_infos_
[uniform_index
] = UniformInfo(
842 size
, type
, uniform_index
, original_name
);
845 UniformInfo
& info
= uniform_infos_
[uniform_index
];
846 info
.element_locations
.resize(size
);
847 info
.element_locations
[0] = location
;
849 size_t num_texture_units
= info
.IsSampler() ? static_cast<size_t>(size
) : 0u;
850 info
.texture_units
.clear();
851 info
.texture_units
.resize(num_texture_units
, 0);
854 // Go through the array element locations looking for a match.
855 // We can skip the first element because it's the same as the
856 // the location without the array operators.
857 size_t array_pos
= name
.rfind(kArraySpec
);
858 std::string base_name
= name
;
859 if (name
.size() > 3) {
860 if (array_pos
!= name
.size() - 3) {
861 info
.name
= name
+ kArraySpec
;
863 base_name
= name
.substr(0, name
.size() - 3);
866 for (GLsizei ii
= 1; ii
< info
.size
; ++ii
) {
867 std::string
element_name(base_name
+ "[" + base::IntToString(ii
) + "]");
868 info
.element_locations
[ii
] =
869 glGetUniformLocation(service_id_
, element_name
.c_str());
875 (info
.name
.size() > 3 &&
876 info
.name
.rfind(kArraySpec
) == info
.name
.size() - 3));
878 if (info
.IsSampler()) {
879 sampler_indices_
.push_back(info
.fake_location_base
);
881 max_uniform_name_length_
=
882 std::max(max_uniform_name_length_
,
883 static_cast<GLsizei
>(info
.name
.size()));
885 while (*next_available_index
< uniform_infos_
.size() &&
886 uniform_infos_
[*next_available_index
].IsValid()) {
887 *next_available_index
= *next_available_index
+ 1;
893 const Program::UniformInfo
*
894 Program::GetUniformInfo(
896 if (static_cast<size_t>(index
) >= uniform_infos_
.size()) {
900 const UniformInfo
& info
= uniform_infos_
[index
];
901 return info
.IsValid() ? &info
: NULL
;
904 bool Program::SetSamplers(
905 GLint num_texture_units
, GLint fake_location
,
906 GLsizei count
, const GLint
* value
) {
907 if (fake_location
< 0) {
910 GLint uniform_index
= GetUniformInfoIndexFromFakeLocation(fake_location
);
911 if (uniform_index
>= 0 &&
912 static_cast<size_t>(uniform_index
) < uniform_infos_
.size()) {
913 UniformInfo
& info
= uniform_infos_
[uniform_index
];
914 if (!info
.IsValid()) {
917 GLint element_index
= GetArrayElementIndexFromFakeLocation(fake_location
);
918 if (element_index
< info
.size
) {
919 count
= std::min(info
.size
- element_index
, count
);
920 if (info
.IsSampler() && count
> 0) {
921 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
922 if (value
[ii
] < 0 || value
[ii
] >= num_texture_units
) {
926 std::copy(value
, value
+ count
,
927 info
.texture_units
.begin() + element_index
);
935 void Program::GetProgramiv(GLenum pname
, GLint
* params
) {
937 case GL_ACTIVE_ATTRIBUTES
:
938 *params
= attrib_infos_
.size();
940 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
:
941 // Notice +1 to accomodate NULL terminator.
942 *params
= max_attrib_name_length_
+ 1;
944 case GL_ACTIVE_UNIFORMS
:
945 *params
= num_uniforms_
;
947 case GL_ACTIVE_UNIFORM_MAX_LENGTH
:
948 // Notice +1 to accomodate NULL terminator.
949 *params
= max_uniform_name_length_
+ 1;
952 *params
= link_status_
;
954 case GL_INFO_LOG_LENGTH
:
955 // Notice +1 to accomodate NULL terminator.
956 *params
= log_info_
.get() ? (log_info_
->size() + 1) : 0;
958 case GL_DELETE_STATUS
:
961 case GL_VALIDATE_STATUS
:
965 glGetProgramiv(service_id_
, pname
, params
);
969 glGetProgramiv(service_id_
, pname
, params
);
974 bool Program::AttachShader(
975 ShaderManager
* shader_manager
,
977 DCHECK(shader_manager
);
979 int index
= ShaderTypeToIndex(shader
->shader_type());
980 if (attached_shaders_
[index
].get() != NULL
) {
983 attached_shaders_
[index
] = scoped_refptr
<Shader
>(shader
);
984 shader_manager
->UseShader(shader
);
988 bool Program::DetachShader(
989 ShaderManager
* shader_manager
,
991 DCHECK(shader_manager
);
993 if (attached_shaders_
[ShaderTypeToIndex(shader
->shader_type())].get() !=
997 attached_shaders_
[ShaderTypeToIndex(shader
->shader_type())] = NULL
;
998 shader_manager
->UnuseShader(shader
);
1002 void Program::DetachShaders(ShaderManager
* shader_manager
) {
1003 DCHECK(shader_manager
);
1004 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1005 if (attached_shaders_
[ii
].get()) {
1006 DetachShader(shader_manager
, attached_shaders_
[ii
].get());
1011 void Program::CompileAttachedShaders() {
1012 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1013 Shader
* shader
= attached_shaders_
[ii
].get();
1015 shader
->DoCompile();
1020 bool Program::AttachedShadersExist() const {
1021 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1022 if (!attached_shaders_
[ii
].get())
1028 bool Program::CanLink() const {
1029 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1030 if (!attached_shaders_
[ii
].get() || !attached_shaders_
[ii
]->valid()) {
1037 bool Program::DetectAttribLocationBindingConflicts() const {
1038 std::set
<GLint
> location_binding_used
;
1039 for (LocationMap::const_iterator it
= bind_attrib_location_map_
.begin();
1040 it
!= bind_attrib_location_map_
.end(); ++it
) {
1041 // Find out if an attribute is statically used in this program's shaders.
1042 const sh::Attribute
* attrib
= NULL
;
1043 const std::string
* mapped_name
= GetAttribMappedName(it
->first
);
1046 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1047 if (!attached_shaders_
[ii
].get() || !attached_shaders_
[ii
]->valid())
1049 attrib
= attached_shaders_
[ii
]->GetAttribInfo(*mapped_name
);
1051 if (attrib
->staticUse
)
1058 size_t num_of_locations
= 1;
1059 switch (attrib
->type
) {
1061 num_of_locations
= 2;
1064 num_of_locations
= 3;
1067 num_of_locations
= 4;
1072 for (size_t ii
= 0; ii
< num_of_locations
; ++ii
) {
1073 GLint loc
= it
->second
+ ii
;
1074 std::pair
<std::set
<GLint
>::iterator
, bool> result
=
1075 location_binding_used
.insert(loc
);
1084 bool Program::DetectUniformsMismatch(std::string
* conflicting_name
) const {
1085 typedef std::map
<std::string
, const sh::Uniform
*> UniformPointerMap
;
1086 UniformPointerMap uniform_pointer_map
;
1087 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1088 const UniformMap
& shader_uniforms
= attached_shaders_
[ii
]->uniform_map();
1089 for (UniformMap::const_iterator iter
= shader_uniforms
.begin();
1090 iter
!= shader_uniforms
.end(); ++iter
) {
1091 const std::string
& name
= iter
->first
;
1092 UniformPointerMap::iterator hit
= uniform_pointer_map
.find(name
);
1093 if (hit
== uniform_pointer_map
.end()) {
1094 uniform_pointer_map
[name
] = &(iter
->second
);
1096 // If a uniform is in the map, i.e., it has already been declared by
1097 // another shader, then the type, precision, etc. must match.
1098 if (hit
->second
->isSameUniformAtLinkTime(iter
->second
))
1100 *conflicting_name
= name
;
1108 bool Program::DetectVaryingsMismatch(std::string
* conflicting_name
) const {
1109 DCHECK(attached_shaders_
[0].get() &&
1110 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1111 attached_shaders_
[1].get() &&
1112 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1113 const VaryingMap
* vertex_varyings
= &(attached_shaders_
[0]->varying_map());
1114 const VaryingMap
* fragment_varyings
= &(attached_shaders_
[1]->varying_map());
1116 for (VaryingMap::const_iterator iter
= fragment_varyings
->begin();
1117 iter
!= fragment_varyings
->end(); ++iter
) {
1118 const std::string
& name
= iter
->first
;
1119 if (IsBuiltInFragmentVarying(name
))
1122 VaryingMap::const_iterator hit
= vertex_varyings
->find(name
);
1123 if (hit
== vertex_varyings
->end()) {
1124 if (iter
->second
.staticUse
) {
1125 *conflicting_name
= name
;
1131 if (!hit
->second
.isSameVaryingAtLinkTime(iter
->second
)) {
1132 *conflicting_name
= name
;
1140 bool Program::DetectBuiltInInvariantConflicts() const {
1141 DCHECK(attached_shaders_
[0].get() &&
1142 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1143 attached_shaders_
[1].get() &&
1144 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1145 const VaryingMap
& vertex_varyings
= attached_shaders_
[0]->varying_map();
1146 const VaryingMap
& fragment_varyings
= attached_shaders_
[1]->varying_map();
1148 bool gl_position_invariant
= IsBuiltInInvariant(
1149 vertex_varyings
, "gl_Position");
1150 bool gl_point_size_invariant
= IsBuiltInInvariant(
1151 vertex_varyings
, "gl_PointSize");
1153 bool gl_frag_coord_invariant
= IsBuiltInInvariant(
1154 fragment_varyings
, "gl_FragCoord");
1155 bool gl_point_coord_invariant
= IsBuiltInInvariant(
1156 fragment_varyings
, "gl_PointCoord");
1158 return ((gl_frag_coord_invariant
&& !gl_position_invariant
) ||
1159 (gl_point_coord_invariant
&& !gl_point_size_invariant
));
1162 bool Program::DetectGlobalNameConflicts(std::string
* conflicting_name
) const {
1163 DCHECK(attached_shaders_
[0].get() &&
1164 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1165 attached_shaders_
[1].get() &&
1166 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1167 const UniformMap
* uniforms
[2];
1168 uniforms
[0] = &(attached_shaders_
[0]->uniform_map());
1169 uniforms
[1] = &(attached_shaders_
[1]->uniform_map());
1170 const AttributeMap
* attribs
=
1171 &(attached_shaders_
[0]->attrib_map());
1173 for (AttributeMap::const_iterator iter
= attribs
->begin();
1174 iter
!= attribs
->end(); ++iter
) {
1175 for (int ii
= 0; ii
< 2; ++ii
) {
1176 if (uniforms
[ii
]->find(iter
->first
) != uniforms
[ii
]->end()) {
1177 *conflicting_name
= iter
->first
;
1185 bool Program::CheckVaryingsPacking(
1186 Program::VaryingsPackingOption option
) const {
1187 DCHECK(attached_shaders_
[0].get() &&
1188 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1189 attached_shaders_
[1].get() &&
1190 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1191 const VaryingMap
* vertex_varyings
= &(attached_shaders_
[0]->varying_map());
1192 const VaryingMap
* fragment_varyings
= &(attached_shaders_
[1]->varying_map());
1194 std::map
<std::string
, ShVariableInfo
> combined_map
;
1196 for (VaryingMap::const_iterator iter
= fragment_varyings
->begin();
1197 iter
!= fragment_varyings
->end(); ++iter
) {
1198 if (!iter
->second
.staticUse
&& option
== kCountOnlyStaticallyUsed
)
1200 if (!IsBuiltInFragmentVarying(iter
->first
)) {
1201 VaryingMap::const_iterator vertex_iter
=
1202 vertex_varyings
->find(iter
->first
);
1203 if (vertex_iter
== vertex_varyings
->end() ||
1204 (!vertex_iter
->second
.staticUse
&&
1205 option
== kCountOnlyStaticallyUsed
))
1210 var
.type
= static_cast<sh::GLenum
>(iter
->second
.type
);
1211 var
.size
= std::max(1u, iter
->second
.arraySize
);
1212 combined_map
[iter
->first
] = var
;
1215 if (combined_map
.size() == 0)
1217 scoped_ptr
<ShVariableInfo
[]> variables(
1218 new ShVariableInfo
[combined_map
.size()]);
1220 for (std::map
<std::string
, ShVariableInfo
>::const_iterator iter
=
1221 combined_map
.begin();
1222 iter
!= combined_map
.end(); ++iter
) {
1223 variables
[index
].type
= iter
->second
.type
;
1224 variables
[index
].size
= iter
->second
.size
;
1227 return ShCheckVariablesWithinPackingLimits(
1228 static_cast<int>(manager_
->max_varying_vectors()),
1230 combined_map
.size());
1233 void Program::GetProgramInfo(
1234 ProgramManager
* manager
, CommonDecoder::Bucket
* bucket
) const {
1235 // NOTE: It seems to me the math in here does not need check for overflow
1236 // because the data being calucated from has various small limits. The max
1237 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1238 // of an identifier is 256 characters.
1239 uint32 num_locations
= 0;
1240 uint32 total_string_size
= 0;
1242 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
1243 const VertexAttrib
& info
= attrib_infos_
[ii
];
1245 total_string_size
+= info
.name
.size();
1248 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
1249 const UniformInfo
& info
= uniform_infos_
[ii
];
1250 if (info
.IsValid()) {
1251 num_locations
+= info
.element_locations
.size();
1252 total_string_size
+= info
.name
.size();
1256 uint32 num_inputs
= attrib_infos_
.size() + num_uniforms_
;
1257 uint32 input_size
= num_inputs
* sizeof(ProgramInput
);
1258 uint32 location_size
= num_locations
* sizeof(int32
);
1259 uint32 size
= sizeof(ProgramInfoHeader
) +
1260 input_size
+ location_size
+ total_string_size
;
1262 bucket
->SetSize(size
);
1263 ProgramInfoHeader
* header
= bucket
->GetDataAs
<ProgramInfoHeader
*>(0, size
);
1264 ProgramInput
* inputs
= bucket
->GetDataAs
<ProgramInput
*>(
1265 sizeof(ProgramInfoHeader
), input_size
);
1266 int32
* locations
= bucket
->GetDataAs
<int32
*>(
1267 sizeof(ProgramInfoHeader
) + input_size
, location_size
);
1268 char* strings
= bucket
->GetDataAs
<char*>(
1269 sizeof(ProgramInfoHeader
) + input_size
+ location_size
,
1276 header
->link_status
= link_status_
;
1277 header
->num_attribs
= attrib_infos_
.size();
1278 header
->num_uniforms
= num_uniforms_
;
1280 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
1281 const VertexAttrib
& info
= attrib_infos_
[ii
];
1282 inputs
->size
= info
.size
;
1283 inputs
->type
= info
.type
;
1284 inputs
->location_offset
= ComputeOffset(header
, locations
);
1285 inputs
->name_offset
= ComputeOffset(header
, strings
);
1286 inputs
->name_length
= info
.name
.size();
1287 *locations
++ = info
.location
;
1288 memcpy(strings
, info
.name
.c_str(), info
.name
.size());
1289 strings
+= info
.name
.size();
1293 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
1294 const UniformInfo
& info
= uniform_infos_
[ii
];
1295 if (info
.IsValid()) {
1296 inputs
->size
= info
.size
;
1297 inputs
->type
= info
.type
;
1298 inputs
->location_offset
= ComputeOffset(header
, locations
);
1299 inputs
->name_offset
= ComputeOffset(header
, strings
);
1300 inputs
->name_length
= info
.name
.size();
1301 DCHECK(static_cast<size_t>(info
.size
) == info
.element_locations
.size());
1302 for (size_t jj
= 0; jj
< info
.element_locations
.size(); ++jj
) {
1303 if (info
.element_locations
[jj
] == -1)
1306 *locations
++ = ProgramManager::MakeFakeLocation(ii
, jj
);
1308 memcpy(strings
, info
.name
.c_str(), info
.name
.size());
1309 strings
+= info
.name
.size();
1314 DCHECK_EQ(ComputeOffset(header
, strings
), size
);
1317 bool Program::GetUniformBlocks(CommonDecoder::Bucket
* bucket
) const {
1318 // The data is packed into the bucket in the following order
1320 // 2) N entries of block data (except for name and indices)
1321 // 3) name1, indices1, name2, indices2, ..., nameN, indicesN
1323 // We query all the data directly through GL calls, assuming they are
1324 // cheap through MANGLE.
1327 GLuint program
= service_id();
1329 uint32_t header_size
= sizeof(UniformBlocksHeader
);
1330 bucket
->SetSize(header_size
); // In case we fail.
1332 uint32_t num_uniform_blocks
= 0;
1333 GLint param
= GL_FALSE
;
1334 // We assume program is a valid program service id.
1335 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1336 if (param
== GL_TRUE
) {
1338 glGetProgramiv(program
, GL_ACTIVE_UNIFORM_BLOCKS
, ¶m
);
1339 num_uniform_blocks
= static_cast<uint32_t>(param
);
1341 if (num_uniform_blocks
== 0) {
1342 // Although spec allows an implementation to return uniform block info
1343 // even if a link fails, for consistency, we disallow that.
1347 std::vector
<UniformBlockInfo
> blocks(num_uniform_blocks
);
1348 base::CheckedNumeric
<uint32_t> size
= sizeof(UniformBlockInfo
);
1349 size
*= num_uniform_blocks
;
1350 uint32_t entry_size
= size
.ValueOrDefault(0);
1351 size
+= header_size
;
1352 std::vector
<std::string
> names(num_uniform_blocks
);
1353 GLint max_name_length
= 0;
1355 program
, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH
, &max_name_length
);
1356 std::vector
<GLchar
> buffer(max_name_length
);
1358 for (uint32_t ii
= 0; ii
< num_uniform_blocks
; ++ii
) {
1360 glGetActiveUniformBlockiv(program
, ii
, GL_UNIFORM_BLOCK_BINDING
, ¶m
);
1361 blocks
[ii
].binding
= static_cast<uint32_t>(param
);
1364 glGetActiveUniformBlockiv(program
, ii
, GL_UNIFORM_BLOCK_DATA_SIZE
, ¶m
);
1365 blocks
[ii
].data_size
= static_cast<uint32_t>(param
);
1367 blocks
[ii
].name_offset
= size
.ValueOrDefault(0);
1369 glGetActiveUniformBlockiv(
1370 program
, ii
, GL_UNIFORM_BLOCK_NAME_LENGTH
, ¶m
);
1371 DCHECK_GE(max_name_length
, param
);
1372 memset(&buffer
[0], 0, param
);
1374 glGetActiveUniformBlockName(
1375 program
, ii
, static_cast<GLsizei
>(param
), &length
, &buffer
[0]);
1376 DCHECK_EQ(param
, length
+ 1);
1377 names
[ii
] = std::string(&buffer
[0], length
);
1378 // TODO(zmo): optimize the name mapping lookup.
1379 const std::string
* original_name
= GetOriginalNameFromHashedName(names
[ii
]);
1381 names
[ii
] = *original_name
;
1382 blocks
[ii
].name_length
= names
[ii
].size() + 1;
1383 size
+= blocks
[ii
].name_length
;
1386 glGetActiveUniformBlockiv(
1387 program
, ii
, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS
, ¶m
);
1388 blocks
[ii
].active_uniforms
= static_cast<uint32_t>(param
);
1389 blocks
[ii
].active_uniform_offset
= size
.ValueOrDefault(0);
1390 base::CheckedNumeric
<uint32_t> indices_size
= blocks
[ii
].active_uniforms
;
1391 indices_size
*= sizeof(uint32_t);
1392 if (!indices_size
.IsValid())
1394 size
+= indices_size
.ValueOrDefault(0);
1397 glGetActiveUniformBlockiv(
1398 program
, ii
, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER
, ¶m
);
1399 blocks
[ii
].referenced_by_vertex_shader
= static_cast<uint32_t>(param
);
1402 glGetActiveUniformBlockiv(
1403 program
, ii
, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
, ¶m
);
1404 blocks
[ii
].referenced_by_fragment_shader
= static_cast<uint32_t>(param
);
1406 if (!size
.IsValid())
1408 uint32_t total_size
= size
.ValueOrDefault(0);
1409 DCHECK_LE(header_size
+ entry_size
, total_size
);
1410 uint32_t data_size
= total_size
- header_size
- entry_size
;
1412 bucket
->SetSize(total_size
);
1413 UniformBlocksHeader
* header
=
1414 bucket
->GetDataAs
<UniformBlocksHeader
*>(0, header_size
);
1415 UniformBlockInfo
* entries
= bucket
->GetDataAs
<UniformBlockInfo
*>(
1416 header_size
, entry_size
);
1417 char* data
= bucket
->GetDataAs
<char*>(header_size
+ entry_size
, data_size
);
1422 // Copy over data for the header and entries.
1423 header
->num_uniform_blocks
= num_uniform_blocks
;
1424 memcpy(entries
, &blocks
[0], entry_size
);
1426 std::vector
<GLint
> params
;
1427 for (uint32_t ii
= 0; ii
< num_uniform_blocks
; ++ii
) {
1428 // Get active uniform name.
1429 memcpy(data
, names
[ii
].c_str(), names
[ii
].length() + 1);
1430 data
+= names
[ii
].length() + 1;
1432 // Get active uniform indices.
1433 if (params
.size() < blocks
[ii
].active_uniforms
)
1434 params
.resize(blocks
[ii
].active_uniforms
);
1435 uint32_t num_bytes
= blocks
[ii
].active_uniforms
* sizeof(GLint
);
1436 memset(¶ms
[0], 0, num_bytes
);
1437 glGetActiveUniformBlockiv(
1438 program
, ii
, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
, ¶ms
[0]);
1439 uint32_t* indices
= reinterpret_cast<uint32_t*>(data
);
1440 for (uint32_t uu
= 0; uu
< blocks
[ii
].active_uniforms
; ++uu
) {
1441 indices
[uu
] = static_cast<uint32_t>(params
[uu
]);
1445 DCHECK_EQ(ComputeOffset(header
, data
), total_size
);
1449 bool Program::GetTransformFeedbackVaryings(
1450 CommonDecoder::Bucket
* bucket
) const {
1451 // The data is packed into the bucket in the following order
1453 // 2) N entries of varying data (except for name)
1454 // 3) name1, name2, ..., nameN
1456 // We query all the data directly through GL calls, assuming they are
1457 // cheap through MANGLE.
1460 GLuint program
= service_id();
1462 uint32_t header_size
= sizeof(TransformFeedbackVaryingsHeader
);
1463 bucket
->SetSize(header_size
); // In case we fail.
1465 uint32_t num_transform_feedback_varyings
= 0;
1466 GLint param
= GL_FALSE
;
1467 // We assume program is a valid program service id.
1468 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1469 if (param
== GL_TRUE
) {
1471 glGetProgramiv(program
, GL_TRANSFORM_FEEDBACK_VARYINGS
, ¶m
);
1472 num_transform_feedback_varyings
= static_cast<uint32_t>(param
);
1474 if (num_transform_feedback_varyings
== 0) {
1478 std::vector
<TransformFeedbackVaryingInfo
> varyings(
1479 num_transform_feedback_varyings
);
1480 base::CheckedNumeric
<uint32_t> size
= sizeof(TransformFeedbackVaryingInfo
);
1481 size
*= num_transform_feedback_varyings
;
1482 uint32_t entry_size
= size
.ValueOrDefault(0);
1483 size
+= header_size
;
1484 std::vector
<std::string
> names(num_transform_feedback_varyings
);
1485 GLint max_name_length
= 0;
1487 program
, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH
, &max_name_length
);
1488 if (max_name_length
< 1)
1489 max_name_length
= 1;
1490 std::vector
<char> buffer(max_name_length
);
1491 for (uint32_t ii
= 0; ii
< num_transform_feedback_varyings
; ++ii
) {
1492 GLsizei var_size
= 0;
1493 GLsizei var_name_length
= 0;
1494 GLenum var_type
= 0;
1495 glGetTransformFeedbackVarying(
1496 program
, ii
, max_name_length
,
1497 &var_name_length
, &var_size
, &var_type
, &buffer
[0]);
1498 varyings
[ii
].size
= static_cast<uint32_t>(var_size
);
1499 varyings
[ii
].type
= static_cast<uint32_t>(var_type
);
1500 varyings
[ii
].name_offset
= static_cast<uint32_t>(size
.ValueOrDefault(0));
1501 DCHECK_GT(max_name_length
, var_name_length
);
1502 names
[ii
] = std::string(&buffer
[0], var_name_length
);
1503 // TODO(zmo): optimize the name mapping lookup.
1504 const std::string
* original_name
= GetOriginalNameFromHashedName(names
[ii
]);
1506 names
[ii
] = *original_name
;
1507 varyings
[ii
].name_length
= names
[ii
].size() + 1;
1508 size
+= names
[ii
].size();
1511 if (!size
.IsValid())
1513 uint32_t total_size
= size
.ValueOrDefault(0);
1514 DCHECK_LE(header_size
+ entry_size
, total_size
);
1515 uint32_t data_size
= total_size
- header_size
- entry_size
;
1517 bucket
->SetSize(total_size
);
1518 TransformFeedbackVaryingsHeader
* header
=
1519 bucket
->GetDataAs
<TransformFeedbackVaryingsHeader
*>(0, header_size
);
1520 TransformFeedbackVaryingInfo
* entries
=
1521 bucket
->GetDataAs
<TransformFeedbackVaryingInfo
*>(header_size
, entry_size
);
1522 char* data
= bucket
->GetDataAs
<char*>(header_size
+ entry_size
, data_size
);
1527 // Copy over data for the header and entries.
1528 header
->num_transform_feedback_varyings
= num_transform_feedback_varyings
;
1529 memcpy(entries
, &varyings
[0], entry_size
);
1531 for (uint32_t ii
= 0; ii
< num_transform_feedback_varyings
; ++ii
) {
1532 memcpy(data
, names
[ii
].c_str(), names
[ii
].length() + 1);
1533 data
+= names
[ii
].length() + 1;
1535 DCHECK_EQ(ComputeOffset(header
, data
), total_size
);
1539 bool Program::GetUniformsES3(CommonDecoder::Bucket
* bucket
) const {
1540 // The data is packed into the bucket in the following order
1542 // 2) N entries of UniformES3Info
1544 // We query all the data directly through GL calls, assuming they are
1545 // cheap through MANGLE.
1548 GLuint program
= service_id();
1550 uint32_t header_size
= sizeof(UniformsES3Header
);
1551 bucket
->SetSize(header_size
); // In case we fail.
1554 GLint param
= GL_FALSE
;
1555 // We assume program is a valid program service id.
1556 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1557 if (param
== GL_TRUE
) {
1559 glGetProgramiv(program
, GL_ACTIVE_UNIFORMS
, &count
);
1565 base::CheckedNumeric
<uint32_t> size
= sizeof(UniformES3Info
);
1567 uint32_t entry_size
= size
.ValueOrDefault(0);
1568 size
+= header_size
;
1569 if (!size
.IsValid())
1571 uint32_t total_size
= size
.ValueOrDefault(0);
1572 bucket
->SetSize(total_size
);
1573 UniformsES3Header
* header
=
1574 bucket
->GetDataAs
<UniformsES3Header
*>(0, header_size
);
1576 header
->num_uniforms
= static_cast<uint32_t>(count
);
1578 // Instead of GetDataAs<UniformES3Info*>, we do GetDataAs<int32_t>. This is
1579 // because struct UniformES3Info is defined as five int32_t.
1580 // By doing this, we can fill the structs through loops.
1582 bucket
->GetDataAs
<int32_t*>(header_size
, entry_size
);
1584 const size_t kStride
= sizeof(UniformES3Info
) / sizeof(int32_t);
1586 const GLenum kPname
[] = {
1587 GL_UNIFORM_BLOCK_INDEX
,
1589 GL_UNIFORM_ARRAY_STRIDE
,
1590 GL_UNIFORM_MATRIX_STRIDE
,
1591 GL_UNIFORM_IS_ROW_MAJOR
,
1593 const GLint kDefaultValue
[] = { -1, -1, -1, -1, 0 };
1594 const size_t kNumPnames
= arraysize(kPname
);
1595 std::vector
<GLuint
> indices(count
);
1596 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1599 std::vector
<GLint
> params(count
);
1600 for (size_t pname_index
= 0; pname_index
< kNumPnames
; ++pname_index
) {
1601 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1602 params
[ii
] = kDefaultValue
[pname_index
];
1604 glGetActiveUniformsiv(
1605 program
, count
, &indices
[0], kPname
[pname_index
], ¶ms
[0]);
1606 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1607 entries
[kStride
* ii
+ pname_index
] = params
[ii
];
1613 void Program::TransformFeedbackVaryings(GLsizei count
,
1614 const char* const* varyings
,
1615 GLenum buffer_mode
) {
1616 transform_feedback_varyings_
.clear();
1617 for (GLsizei i
= 0; i
< count
; ++i
) {
1618 transform_feedback_varyings_
.push_back(std::string(varyings
[i
]));
1620 transform_feedback_buffer_mode_
= buffer_mode
;
1623 Program::~Program() {
1625 if (manager_
->have_context_
) {
1626 glDeleteProgram(service_id());
1628 manager_
->StopTracking(this);
1634 ProgramManager::ProgramManager(ProgramCache
* program_cache
,
1635 uint32 max_varying_vectors
)
1636 : program_count_(0),
1637 have_context_(true),
1638 program_cache_(program_cache
),
1639 max_varying_vectors_(max_varying_vectors
) { }
1641 ProgramManager::~ProgramManager() {
1642 DCHECK(programs_
.empty());
1645 void ProgramManager::Destroy(bool have_context
) {
1646 have_context_
= have_context
;
1650 void ProgramManager::StartTracking(Program
* /* program */) {
1654 void ProgramManager::StopTracking(Program
* /* program */) {
1658 Program
* ProgramManager::CreateProgram(
1659 GLuint client_id
, GLuint service_id
) {
1660 std::pair
<ProgramMap::iterator
, bool> result
=
1662 std::make_pair(client_id
,
1663 scoped_refptr
<Program
>(
1664 new Program(this, service_id
))));
1665 DCHECK(result
.second
);
1666 return result
.first
->second
.get();
1669 Program
* ProgramManager::GetProgram(GLuint client_id
) {
1670 ProgramMap::iterator it
= programs_
.find(client_id
);
1671 return it
!= programs_
.end() ? it
->second
.get() : NULL
;
1674 bool ProgramManager::GetClientId(GLuint service_id
, GLuint
* client_id
) const {
1675 // This doesn't need to be fast. It's only used during slow queries.
1676 for (ProgramMap::const_iterator it
= programs_
.begin();
1677 it
!= programs_
.end(); ++it
) {
1678 if (it
->second
->service_id() == service_id
) {
1679 *client_id
= it
->first
;
1686 ProgramCache
* ProgramManager::program_cache() const {
1687 return program_cache_
;
1690 bool ProgramManager::IsOwned(Program
* program
) {
1691 for (ProgramMap::iterator it
= programs_
.begin();
1692 it
!= programs_
.end(); ++it
) {
1693 if (it
->second
.get() == program
) {
1700 void ProgramManager::RemoveProgramInfoIfUnused(
1701 ShaderManager
* shader_manager
, Program
* program
) {
1702 DCHECK(shader_manager
);
1704 DCHECK(IsOwned(program
));
1705 if (program
->IsDeleted() && !program
->InUse()) {
1706 program
->DetachShaders(shader_manager
);
1707 for (ProgramMap::iterator it
= programs_
.begin();
1708 it
!= programs_
.end(); ++it
) {
1709 if (it
->second
.get() == program
) {
1710 programs_
.erase(it
);
1718 void ProgramManager::MarkAsDeleted(
1719 ShaderManager
* shader_manager
,
1721 DCHECK(shader_manager
);
1723 DCHECK(IsOwned(program
));
1724 program
->MarkAsDeleted();
1725 RemoveProgramInfoIfUnused(shader_manager
, program
);
1728 void ProgramManager::UseProgram(Program
* program
) {
1730 DCHECK(IsOwned(program
));
1731 program
->IncUseCount();
1734 void ProgramManager::UnuseProgram(
1735 ShaderManager
* shader_manager
,
1737 DCHECK(shader_manager
);
1739 DCHECK(IsOwned(program
));
1740 program
->DecUseCount();
1741 RemoveProgramInfoIfUnused(shader_manager
, program
);
1744 void ProgramManager::ClearUniforms(Program
* program
) {
1746 program
->ClearUniforms(&zero_
);
1749 int32
ProgramManager::MakeFakeLocation(int32 index
, int32 element
) {
1750 return index
+ element
* 0x10000;
1753 } // namespace gles2