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/strings/string_number_conversions.h"
18 #include "base/time/time.h"
19 #include "gpu/command_buffer/common/gles2_cmd_format.h"
20 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
21 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
22 #include "gpu/command_buffer/service/gpu_switches.h"
23 #include "gpu/command_buffer/service/program_cache.h"
24 #include "gpu/command_buffer/service/shader_manager.h"
25 #include "gpu/command_buffer/service/shader_translator.h"
26 #include "third_party/re2/re2/re2.h"
28 using base::TimeDelta
;
29 using base::TimeTicks
;
37 explicit UniformType(const ShaderTranslator::VariableInfo uniform
)
40 precision(uniform
.precision
) { }
45 precision(SH_PRECISION_MEDIUMP
) { }
47 bool operator==(const UniformType
& other
) const {
48 return type
== other
.type
&&
50 precision
== other
.precision
;
58 int ShaderTypeToIndex(GLenum shader_type
) {
59 switch (shader_type
) {
60 case GL_VERTEX_SHADER
:
62 case GL_FRAGMENT_SHADER
:
70 // Given a name like "foo.bar[123].moo[456]" sets new_name to "foo.bar[123].moo"
71 // and sets element_index to 456. returns false if element expression was not a
72 // whole decimal number. For example: "foo[1b2]"
73 bool GetUniformNameSansElement(
74 const std::string
& name
, int* element_index
, std::string
* new_name
) {
75 DCHECK(element_index
);
77 if (name
.size() < 3 || name
[name
.size() - 1] != ']') {
83 // Look for an array specification.
84 size_t open_pos
= name
.find_last_of('[');
85 if (open_pos
== std::string::npos
||
86 open_pos
>= name
.size() - 2) {
91 size_t last
= name
.size() - 1;
92 for (size_t pos
= open_pos
+ 1; pos
< last
; ++pos
) {
93 int8 digit
= name
[pos
] - '0';
94 if (digit
< 0 || digit
> 9) {
97 index
= index
* 10 + digit
;
100 *element_index
= index
;
101 *new_name
= name
.substr(0, open_pos
);
105 bool IsBuiltInVarying(const std::string
& name
) {
106 // Built-in variables.
107 const char* kBuiltInVaryings
[] = {
112 for (size_t ii
= 0; ii
< arraysize(kBuiltInVaryings
); ++ii
) {
113 if (name
== kBuiltInVaryings
[ii
])
119 } // anonymous namespace.
121 Program::UniformInfo::UniformInfo()
124 fake_location_base(0),
128 Program::UniformInfo::UniformInfo(GLsizei _size
,
130 int _fake_location_base
,
131 const std::string
& _name
)
135 fake_location_base(_fake_location_base
),
140 accepts_api_type
= kUniform1i
;
143 accepts_api_type
= kUniform2i
;
146 accepts_api_type
= kUniform3i
;
149 accepts_api_type
= kUniform4i
;
153 accepts_api_type
= kUniform1i
| kUniform1f
;
156 accepts_api_type
= kUniform2i
| kUniform2f
;
159 accepts_api_type
= kUniform3i
| kUniform3f
;
162 accepts_api_type
= kUniform4i
| kUniform4f
;
166 accepts_api_type
= kUniform1f
;
169 accepts_api_type
= kUniform2f
;
172 accepts_api_type
= kUniform3f
;
175 accepts_api_type
= kUniform4f
;
179 accepts_api_type
= kUniformMatrix2f
;
182 accepts_api_type
= kUniformMatrix3f
;
185 accepts_api_type
= kUniformMatrix4f
;
189 case GL_SAMPLER_2D_RECT_ARB
:
190 case GL_SAMPLER_CUBE
:
191 case GL_SAMPLER_3D_OES
:
192 case GL_SAMPLER_EXTERNAL_OES
:
193 accepts_api_type
= kUniform1i
;
196 NOTREACHED() << "Unhandled UniformInfo type " << type
;
201 Program::UniformInfo::~UniformInfo() {}
203 bool ProgramManager::IsInvalidPrefix(const char* name
, size_t length
) {
204 static const char kInvalidPrefix
[] = { 'g', 'l', '_' };
205 return (length
>= sizeof(kInvalidPrefix
) &&
206 memcmp(name
, kInvalidPrefix
, sizeof(kInvalidPrefix
)) == 0);
210 ProgramManager
* manager
, GLuint service_id
)
213 max_attrib_name_length_(0),
214 max_uniform_name_length_(0),
215 service_id_(service_id
),
219 uniforms_cleared_(false),
221 manager_
->StartTracking(this);
224 void Program::Reset() {
226 link_status_
= false;
228 max_uniform_name_length_
= 0;
229 max_attrib_name_length_
= 0;
230 attrib_infos_
.clear();
231 uniform_infos_
.clear();
232 sampler_indices_
.clear();
233 attrib_location_to_index_map_
.clear();
236 std::string
Program::ProcessLogInfo(
237 const std::string
& log
) {
239 re2::StringPiece
input(log
);
240 std::string prior_log
;
241 std::string hashed_name
;
242 while (RE2::Consume(&input
,
243 "(.*?)(webgl_[0123456789abcdefABCDEF]+)",
248 const std::string
* original_name
=
249 GetOriginalNameFromHashedName(hashed_name
);
251 output
+= *original_name
;
253 output
+= hashed_name
;
256 return output
+ input
.as_string();
259 void Program::UpdateLogInfo() {
261 glGetProgramiv(service_id_
, GL_INFO_LOG_LENGTH
, &max_len
);
266 scoped_ptr
<char[]> temp(new char[max_len
]);
268 glGetProgramInfoLog(service_id_
, max_len
, &len
, temp
.get());
269 DCHECK(max_len
== 0 || len
< max_len
);
270 DCHECK(len
== 0 || temp
[len
] == '\0');
271 std::string
log(temp
.get(), len
);
272 set_log_info(ProcessLogInfo(log
).c_str());
275 void Program::ClearUniforms(
276 std::vector
<uint8
>* zero_buffer
) {
278 if (uniforms_cleared_
) {
281 uniforms_cleared_
= true;
282 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
283 const UniformInfo
& uniform_info
= uniform_infos_
[ii
];
284 if (!uniform_info
.IsValid()) {
287 GLint location
= uniform_info
.element_locations
[0];
288 GLsizei size
= uniform_info
.size
;
289 uint32 unit_size
= GLES2Util::GetGLDataTypeSizeForUniforms(
291 uint32 size_needed
= size
* unit_size
;
292 if (size_needed
> zero_buffer
->size()) {
293 zero_buffer
->resize(size_needed
, 0u);
295 const void* zero
= &(*zero_buffer
)[0];
296 switch (uniform_info
.type
) {
298 glUniform1fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
301 glUniform2fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
304 glUniform3fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
307 glUniform4fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
312 case GL_SAMPLER_CUBE
:
313 case GL_SAMPLER_EXTERNAL_OES
:
314 case GL_SAMPLER_3D_OES
:
315 case GL_SAMPLER_2D_RECT_ARB
:
316 glUniform1iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
320 glUniform2iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
324 glUniform3iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
328 glUniform4iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
332 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
336 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
340 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
352 UniformData() : size(-1), type(GL_NONE
), location(0), added(false) {
354 std::string queried_name
;
355 std::string corrected_name
;
356 std::string original_name
;
363 struct UniformDataComparer
{
364 bool operator()(const UniformData
& lhs
, const UniformData
& rhs
) const {
365 return lhs
.queried_name
< rhs
.queried_name
;
369 } // anonymous namespace
371 void Program::Update() {
375 uniforms_cleared_
= false;
376 GLint num_attribs
= 0;
378 GLint max_location
= -1;
379 glGetProgramiv(service_id_
, GL_ACTIVE_ATTRIBUTES
, &num_attribs
);
380 glGetProgramiv(service_id_
, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
, &max_len
);
381 // TODO(gman): Should we check for error?
382 scoped_ptr
<char[]> name_buffer(new char[max_len
]);
383 for (GLint ii
= 0; ii
< num_attribs
; ++ii
) {
388 service_id_
, ii
, max_len
, &length
, &size
, &type
, name_buffer
.get());
389 DCHECK(max_len
== 0 || length
< max_len
);
390 DCHECK(length
== 0 || name_buffer
[length
] == '\0');
391 if (!ProgramManager::IsInvalidPrefix(name_buffer
.get(), length
)) {
393 std::string original_name
;
394 GetCorrectedVariableInfo(
395 false, name_buffer
.get(), &name
, &original_name
, &size
, &type
);
396 // TODO(gman): Should we check for error?
397 GLint location
= glGetAttribLocation(service_id_
, name_buffer
.get());
398 if (location
> max_location
) {
399 max_location
= location
;
401 attrib_infos_
.push_back(
402 VertexAttrib(size
, type
, original_name
, location
));
403 max_attrib_name_length_
= std::max(
404 max_attrib_name_length_
, static_cast<GLsizei
>(original_name
.size()));
408 // Create attrib location to index map.
409 attrib_location_to_index_map_
.resize(max_location
+ 1);
410 for (GLint ii
= 0; ii
<= max_location
; ++ii
) {
411 attrib_location_to_index_map_
[ii
] = -1;
413 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
414 const VertexAttrib
& info
= attrib_infos_
[ii
];
415 attrib_location_to_index_map_
[info
.location
] = ii
;
419 if (CommandLine::ForCurrentProcess()->HasSwitch(
420 switches::kEnableGPUServiceLoggingGPU
)) {
421 DVLOG(1) << "----: attribs for service_id: " << service_id();
422 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
423 const VertexAttrib
& info
= attrib_infos_
[ii
];
424 DVLOG(1) << ii
<< ": loc = " << info
.location
425 << ", size = " << info
.size
426 << ", type = " << GLES2Util::GetStringEnum(info
.type
)
427 << ", name = " << info
.name
;
433 GLint num_uniforms
= 0;
434 glGetProgramiv(service_id_
, GL_ACTIVE_UNIFORMS
, &num_uniforms
);
435 glGetProgramiv(service_id_
, GL_ACTIVE_UNIFORM_MAX_LENGTH
, &max_len
);
436 name_buffer
.reset(new char[max_len
]);
438 // Reads all the names.
439 std::vector
<UniformData
> uniform_data
;
440 for (GLint ii
= 0; ii
< num_uniforms
; ++ii
) {
444 service_id_
, ii
, max_len
, &length
,
445 &data
.size
, &data
.type
, name_buffer
.get());
446 DCHECK(max_len
== 0 || length
< max_len
);
447 DCHECK(length
== 0 || name_buffer
[length
] == '\0');
448 if (!ProgramManager::IsInvalidPrefix(name_buffer
.get(), length
)) {
449 data
.queried_name
= std::string(name_buffer
.get());
450 GetCorrectedVariableInfo(
451 true, name_buffer
.get(), &data
.corrected_name
, &data
.original_name
,
452 &data
.size
, &data
.type
);
453 uniform_data
.push_back(data
);
457 // NOTE: We don't care if 2 uniforms are bound to the same location.
458 // One of them will take preference. The spec allows this, same as
459 // BindAttribLocation.
461 // The reason we don't check is if we were to fail we'd have to
462 // restore the previous program but since we've already linked successfully
463 // at this point the previous program is gone.
465 // Assigns the uniforms with bindings.
466 size_t next_available_index
= 0;
467 for (size_t ii
= 0; ii
< uniform_data
.size(); ++ii
) {
468 UniformData
& data
= uniform_data
[ii
];
469 data
.location
= glGetUniformLocation(
470 service_id_
, data
.queried_name
.c_str());
472 std::string short_name
;
473 int element_index
= 0;
474 bool good ALLOW_UNUSED
= GetUniformNameSansElement(
475 data
.queried_name
, &element_index
, &short_name
);\
477 LocationMap::const_iterator it
= bind_uniform_location_map_
.find(
479 if (it
!= bind_uniform_location_map_
.end()) {
480 data
.added
= AddUniformInfo(
481 data
.size
, data
.type
, data
.location
, it
->second
, data
.corrected_name
,
482 data
.original_name
, &next_available_index
);
486 // Assigns the uniforms that were not bound.
487 for (size_t ii
= 0; ii
< uniform_data
.size(); ++ii
) {
488 const UniformData
& data
= uniform_data
[ii
];
491 data
.size
, data
.type
, data
.location
, -1, data
.corrected_name
,
492 data
.original_name
, &next_available_index
);
497 if (CommandLine::ForCurrentProcess()->HasSwitch(
498 switches::kEnableGPUServiceLoggingGPU
)) {
499 DVLOG(1) << "----: uniforms for service_id: " << service_id();
500 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
501 const UniformInfo
& info
= uniform_infos_
[ii
];
502 if (info
.IsValid()) {
503 DVLOG(1) << ii
<< ": loc = " << info
.element_locations
[0]
504 << ", size = " << info
.size
505 << ", type = " << GLES2Util::GetStringEnum(info
.type
)
506 << ", name = " << info
.name
;
515 void Program::ExecuteBindAttribLocationCalls() {
516 for (LocationMap::const_iterator it
= bind_attrib_location_map_
.begin();
517 it
!= bind_attrib_location_map_
.end(); ++it
) {
518 const std::string
* mapped_name
= GetAttribMappedName(it
->first
);
519 if (mapped_name
&& *mapped_name
!= it
->first
)
520 glBindAttribLocation(service_id_
, it
->second
, mapped_name
->c_str());
524 void ProgramManager::DoCompileShader(
526 ShaderTranslator
* translator
,
527 ProgramManager::TranslatedShaderSourceType translated_shader_source_type
) {
528 // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
529 // glShaderSource and then glCompileShader.
530 const std::string
* source
= shader
->source();
531 const char* shader_src
= source
? source
->c_str() : "";
533 if (!translator
->Translate(shader_src
)) {
534 shader
->SetStatus(false, translator
->info_log(), NULL
);
537 shader_src
= translator
->translated_shader();
538 if (translated_shader_source_type
!= kANGLE
)
539 shader
->UpdateTranslatedSource(shader_src
);
542 glShaderSource(shader
->service_id(), 1, &shader_src
, NULL
);
543 glCompileShader(shader
->service_id());
544 if (translated_shader_source_type
== kANGLE
) {
546 glGetShaderiv(shader
->service_id(),
547 GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE
,
549 scoped_ptr
<char[]> temp(new char[max_len
]);
551 glGetTranslatedShaderSourceANGLE(
552 shader
->service_id(), max_len
, &len
, temp
.get());
553 DCHECK(max_len
== 0 || len
< max_len
);
554 DCHECK(len
== 0 || temp
[len
] == '\0');
555 shader
->UpdateTranslatedSource(max_len
? temp
.get() : NULL
);
558 GLint status
= GL_FALSE
;
559 glGetShaderiv(shader
->service_id(), GL_COMPILE_STATUS
, &status
);
561 shader
->SetStatus(true, "", translator
);
563 // We cannot reach here if we are using the shader translator.
564 // All invalid shaders must be rejected by the translator.
565 // All translated shaders must compile.
567 glGetShaderiv(shader
->service_id(), GL_INFO_LOG_LENGTH
, &max_len
);
568 scoped_ptr
<char[]> temp(new char[max_len
]);
570 glGetShaderInfoLog(shader
->service_id(), max_len
, &len
, temp
.get());
571 DCHECK(max_len
== 0 || len
< max_len
);
572 DCHECK(len
== 0 || temp
[len
] == '\0');
573 shader
->SetStatus(false, std::string(temp
.get(), len
).c_str(), NULL
);
574 LOG_IF(ERROR
, translator
)
575 << "Shader translator allowed/produced an invalid shader "
576 << "unless the driver is buggy:"
577 << "\n--original-shader--\n" << (source
? *source
: std::string())
578 << "\n--translated-shader--\n" << shader_src
<< "\n--info-log--\n"
579 << *shader
->log_info();
583 bool Program::Link(ShaderManager
* manager
,
584 ShaderTranslator
* vertex_translator
,
585 ShaderTranslator
* fragment_translator
,
586 Program::VaryingsPackingOption varyings_packing_option
,
587 const ShaderCacheCallback
& shader_callback
) {
590 set_log_info("missing shaders");
593 if (DetectAttribLocationBindingConflicts()) {
594 set_log_info("glBindAttribLocation() conflicts");
597 std::string conflicting_name
;
598 if (DetectUniformsMismatch(&conflicting_name
)) {
599 std::string info_log
= "Uniforms with the same name but different "
600 "type/precision: " + conflicting_name
;
601 set_log_info(ProcessLogInfo(info_log
).c_str());
604 if (DetectVaryingsMismatch(&conflicting_name
)) {
605 std::string info_log
= "Varyings with the same name but different type, "
606 "or statically used varyings in fragment shader are "
607 "not declared in vertex shader: " + conflicting_name
;
608 set_log_info(ProcessLogInfo(info_log
).c_str());
611 if (DetectGlobalNameConflicts(&conflicting_name
)) {
612 std::string info_log
= "Name conflicts between an uniform and an "
613 "attribute: " + conflicting_name
;
614 set_log_info(ProcessLogInfo(info_log
).c_str());
617 if (!CheckVaryingsPacking(varyings_packing_option
)) {
618 set_log_info("Varyings over maximum register limit");
622 TimeTicks before_time
= TimeTicks::HighResNow();
624 ProgramCache
* cache
= manager_
->program_cache_
;
626 DCHECK(attached_shaders_
[0]->signature_source() &&
627 attached_shaders_
[1]->signature_source());
628 ProgramCache::LinkedProgramStatus status
= cache
->GetLinkedProgramStatus(
629 *attached_shaders_
[0]->signature_source(),
631 *attached_shaders_
[1]->signature_source(),
633 &bind_attrib_location_map_
);
635 if (status
== ProgramCache::LINK_SUCCEEDED
) {
636 ProgramCache::ProgramLoadResult success
=
637 cache
->LoadLinkedProgram(service_id(),
638 attached_shaders_
[0].get(),
640 attached_shaders_
[1].get(),
642 &bind_attrib_location_map_
,
644 link
= success
!= ProgramCache::PROGRAM_LOAD_SUCCESS
;
645 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link
);
650 ExecuteBindAttribLocationCalls();
651 before_time
= TimeTicks::HighResNow();
652 if (cache
&& gfx::g_driver_gl
.ext
.b_GL_ARB_get_program_binary
) {
653 glProgramParameteri(service_id(),
654 PROGRAM_BINARY_RETRIEVABLE_HINT
,
657 glLinkProgram(service_id());
661 glGetProgramiv(service_id(), GL_LINK_STATUS
, &success
);
662 if (success
== GL_TRUE
) {
666 cache
->SaveLinkedProgram(service_id(),
667 attached_shaders_
[0].get(),
669 attached_shaders_
[1].get(),
671 &bind_attrib_location_map_
,
674 UMA_HISTOGRAM_CUSTOM_COUNTS(
675 "GPU.ProgramCache.BinaryCacheMissTime",
676 (TimeTicks::HighResNow() - before_time
).InMicroseconds(),
678 TimeDelta::FromSeconds(10).InMicroseconds(),
681 UMA_HISTOGRAM_CUSTOM_COUNTS(
682 "GPU.ProgramCache.BinaryCacheHitTime",
683 (TimeTicks::HighResNow() - before_time
).InMicroseconds(),
685 TimeDelta::FromSeconds(1).InMicroseconds(),
691 return success
== GL_TRUE
;
694 void Program::Validate() {
696 set_log_info("program not linked");
699 glValidateProgram(service_id());
703 GLint
Program::GetUniformFakeLocation(
704 const std::string
& name
) const {
705 bool getting_array_location
= false;
706 size_t open_pos
= std::string::npos
;
708 if (!GLES2Util::ParseUniformName(
709 name
, &open_pos
, &index
, &getting_array_location
)) {
712 for (GLuint ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
713 const UniformInfo
& info
= uniform_infos_
[ii
];
714 if (!info
.IsValid()) {
717 if (info
.name
== name
||
719 info
.name
.compare(0, info
.name
.size() - 3, name
) == 0)) {
720 return info
.fake_location_base
;
721 } else if (getting_array_location
&& info
.is_array
) {
722 // Look for an array specification.
723 size_t open_pos_2
= info
.name
.find_last_of('[');
724 if (open_pos_2
== open_pos
&&
725 name
.compare(0, open_pos
, info
.name
, 0, open_pos
) == 0) {
726 if (index
>= 0 && index
< info
.size
) {
727 DCHECK_GT(static_cast<int>(info
.element_locations
.size()), index
);
728 if (info
.element_locations
[index
] == -1)
730 return ProgramManager::MakeFakeLocation(
731 info
.fake_location_base
, index
);
739 GLint
Program::GetAttribLocation(
740 const std::string
& name
) const {
741 for (GLuint ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
742 const VertexAttrib
& info
= attrib_infos_
[ii
];
743 if (info
.name
== name
) {
744 return info
.location
;
750 const Program::UniformInfo
*
751 Program::GetUniformInfoByFakeLocation(
752 GLint fake_location
, GLint
* real_location
, GLint
* array_index
) const {
753 DCHECK(real_location
);
755 if (fake_location
< 0) {
759 GLint uniform_index
= GetUniformInfoIndexFromFakeLocation(fake_location
);
760 if (uniform_index
>= 0 &&
761 static_cast<size_t>(uniform_index
) < uniform_infos_
.size()) {
762 const UniformInfo
& uniform_info
= uniform_infos_
[uniform_index
];
763 if (!uniform_info
.IsValid()) {
766 GLint element_index
= GetArrayElementIndexFromFakeLocation(fake_location
);
767 if (element_index
< uniform_info
.size
) {
768 *real_location
= uniform_info
.element_locations
[element_index
];
769 *array_index
= element_index
;
770 return &uniform_info
;
776 const std::string
* Program::GetAttribMappedName(
777 const std::string
& original_name
) const {
778 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
779 Shader
* shader
= attached_shaders_
[ii
].get();
781 const std::string
* mapped_name
=
782 shader
->GetAttribMappedName(original_name
);
790 const std::string
* Program::GetOriginalNameFromHashedName(
791 const std::string
& hashed_name
) const {
792 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
793 Shader
* shader
= attached_shaders_
[ii
].get();
795 const std::string
* original_name
=
796 shader
->GetOriginalNameFromHashedName(hashed_name
);
798 return original_name
;
804 bool Program::SetUniformLocationBinding(
805 const std::string
& name
, GLint location
) {
806 std::string short_name
;
807 int element_index
= 0;
808 if (!GetUniformNameSansElement(name
, &element_index
, &short_name
) ||
809 element_index
!= 0) {
813 bind_uniform_location_map_
[short_name
] = location
;
817 // Note: This is only valid to call right after a program has been linked
819 void Program::GetCorrectedVariableInfo(
821 const std::string
& name
, std::string
* corrected_name
,
822 std::string
* original_name
,
823 GLsizei
* size
, GLenum
* type
) const {
824 DCHECK(corrected_name
);
825 DCHECK(original_name
);
828 const char* kArraySpec
= "[0]";
829 for (int jj
= 0; jj
< 2; ++jj
) {
830 std::string
test_name(name
+ ((jj
== 1) ? kArraySpec
: ""));
831 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
832 Shader
* shader
= attached_shaders_
[ii
].get();
834 const Shader::VariableInfo
* variable_info
=
835 use_uniforms
? shader
->GetUniformInfo(test_name
) :
836 shader
->GetAttribInfo(test_name
);
837 // Note: There is an assuption here that if an attrib is defined in more
838 // than 1 attached shader their types and sizes match. Should we check
841 *corrected_name
= test_name
;
842 *original_name
= variable_info
->name
;
843 *type
= variable_info
->type
;
844 *size
= variable_info
->size
;
850 *corrected_name
= name
;
851 *original_name
= name
;
854 bool Program::AddUniformInfo(
855 GLsizei size
, GLenum type
, GLint location
, GLint fake_base_location
,
856 const std::string
& name
, const std::string
& original_name
,
857 size_t* next_available_index
) {
858 DCHECK(next_available_index
);
859 const char* kArraySpec
= "[0]";
860 size_t uniform_index
=
861 fake_base_location
>= 0 ? fake_base_location
: *next_available_index
;
862 if (uniform_infos_
.size() < uniform_index
+ 1) {
863 uniform_infos_
.resize(uniform_index
+ 1);
866 // return if this location is already in use.
867 if (uniform_infos_
[uniform_index
].IsValid()) {
868 DCHECK_GE(fake_base_location
, 0);
872 uniform_infos_
[uniform_index
] = UniformInfo(
873 size
, type
, uniform_index
, original_name
);
876 UniformInfo
& info
= uniform_infos_
[uniform_index
];
877 info
.element_locations
.resize(size
);
878 info
.element_locations
[0] = location
;
880 size_t num_texture_units
= info
.IsSampler() ? static_cast<size_t>(size
) : 0u;
881 info
.texture_units
.clear();
882 info
.texture_units
.resize(num_texture_units
, 0);
885 // Go through the array element locations looking for a match.
886 // We can skip the first element because it's the same as the
887 // the location without the array operators.
888 size_t array_pos
= name
.rfind(kArraySpec
);
889 std::string base_name
= name
;
890 if (name
.size() > 3) {
891 if (array_pos
!= name
.size() - 3) {
892 info
.name
= name
+ kArraySpec
;
894 base_name
= name
.substr(0, name
.size() - 3);
897 for (GLsizei ii
= 1; ii
< info
.size
; ++ii
) {
898 std::string
element_name(base_name
+ "[" + base::IntToString(ii
) + "]");
899 info
.element_locations
[ii
] =
900 glGetUniformLocation(service_id_
, element_name
.c_str());
906 (info
.name
.size() > 3 &&
907 info
.name
.rfind(kArraySpec
) == info
.name
.size() - 3));
909 if (info
.IsSampler()) {
910 sampler_indices_
.push_back(info
.fake_location_base
);
912 max_uniform_name_length_
=
913 std::max(max_uniform_name_length_
,
914 static_cast<GLsizei
>(info
.name
.size()));
916 while (*next_available_index
< uniform_infos_
.size() &&
917 uniform_infos_
[*next_available_index
].IsValid()) {
918 *next_available_index
= *next_available_index
+ 1;
924 const Program::UniformInfo
*
925 Program::GetUniformInfo(
927 if (static_cast<size_t>(index
) >= uniform_infos_
.size()) {
931 const UniformInfo
& info
= uniform_infos_
[index
];
932 return info
.IsValid() ? &info
: NULL
;
935 bool Program::SetSamplers(
936 GLint num_texture_units
, GLint fake_location
,
937 GLsizei count
, const GLint
* value
) {
938 if (fake_location
< 0) {
941 GLint uniform_index
= GetUniformInfoIndexFromFakeLocation(fake_location
);
942 if (uniform_index
>= 0 &&
943 static_cast<size_t>(uniform_index
) < uniform_infos_
.size()) {
944 UniformInfo
& info
= uniform_infos_
[uniform_index
];
945 if (!info
.IsValid()) {
948 GLint element_index
= GetArrayElementIndexFromFakeLocation(fake_location
);
949 if (element_index
< info
.size
) {
950 count
= std::min(info
.size
- element_index
, count
);
951 if (info
.IsSampler() && count
> 0) {
952 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
953 if (value
[ii
] < 0 || value
[ii
] >= num_texture_units
) {
957 std::copy(value
, value
+ count
,
958 info
.texture_units
.begin() + element_index
);
966 void Program::GetProgramiv(GLenum pname
, GLint
* params
) {
968 case GL_ACTIVE_ATTRIBUTES
:
969 *params
= attrib_infos_
.size();
971 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
:
972 // Notice +1 to accomodate NULL terminator.
973 *params
= max_attrib_name_length_
+ 1;
975 case GL_ACTIVE_UNIFORMS
:
976 *params
= num_uniforms_
;
978 case GL_ACTIVE_UNIFORM_MAX_LENGTH
:
979 // Notice +1 to accomodate NULL terminator.
980 *params
= max_uniform_name_length_
+ 1;
983 *params
= link_status_
;
985 case GL_INFO_LOG_LENGTH
:
986 // Notice +1 to accomodate NULL terminator.
987 *params
= log_info_
.get() ? (log_info_
->size() + 1) : 0;
989 case GL_DELETE_STATUS
:
992 case GL_VALIDATE_STATUS
:
996 glGetProgramiv(service_id_
, pname
, params
);
1000 glGetProgramiv(service_id_
, pname
, params
);
1005 bool Program::AttachShader(
1006 ShaderManager
* shader_manager
,
1008 DCHECK(shader_manager
);
1010 int index
= ShaderTypeToIndex(shader
->shader_type());
1011 if (attached_shaders_
[index
].get() != NULL
) {
1014 attached_shaders_
[index
] = scoped_refptr
<Shader
>(shader
);
1015 shader_manager
->UseShader(shader
);
1019 bool Program::DetachShader(
1020 ShaderManager
* shader_manager
,
1022 DCHECK(shader_manager
);
1024 if (attached_shaders_
[ShaderTypeToIndex(shader
->shader_type())].get() !=
1028 attached_shaders_
[ShaderTypeToIndex(shader
->shader_type())] = NULL
;
1029 shader_manager
->UnuseShader(shader
);
1033 void Program::DetachShaders(ShaderManager
* shader_manager
) {
1034 DCHECK(shader_manager
);
1035 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1036 if (attached_shaders_
[ii
].get()) {
1037 DetachShader(shader_manager
, attached_shaders_
[ii
].get());
1042 bool Program::CanLink() const {
1043 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1044 if (!attached_shaders_
[ii
].get() || !attached_shaders_
[ii
]->IsValid()) {
1051 bool Program::DetectAttribLocationBindingConflicts() const {
1052 std::set
<GLint
> location_binding_used
;
1053 for (LocationMap::const_iterator it
= bind_attrib_location_map_
.begin();
1054 it
!= bind_attrib_location_map_
.end(); ++it
) {
1055 // Find out if an attribute is declared in this program's shaders.
1056 bool active
= false;
1057 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1058 if (!attached_shaders_
[ii
].get() || !attached_shaders_
[ii
]->IsValid())
1060 if (attached_shaders_
[ii
]->GetAttribInfo(it
->first
)) {
1066 std::pair
<std::set
<GLint
>::iterator
, bool> result
=
1067 location_binding_used
.insert(it
->second
);
1075 bool Program::DetectUniformsMismatch(std::string
* conflicting_name
) const {
1076 typedef std::map
<std::string
, UniformType
> UniformMap
;
1077 UniformMap uniform_map
;
1078 for (int ii
= 0; ii
< kMaxAttachedShaders
; ++ii
) {
1079 const ShaderTranslator::VariableMap
& shader_uniforms
=
1080 attached_shaders_
[ii
]->uniform_map();
1081 for (ShaderTranslator::VariableMap::const_iterator iter
=
1082 shader_uniforms
.begin();
1083 iter
!= shader_uniforms
.end(); ++iter
) {
1084 const std::string
& name
= iter
->first
;
1085 UniformType
type(iter
->second
);
1086 UniformMap::iterator map_entry
= uniform_map
.find(name
);
1087 if (map_entry
== uniform_map
.end()) {
1088 uniform_map
[name
] = type
;
1090 // If a uniform is already in the map, i.e., it has already been
1091 // declared by other shader, then the type and precision must match.
1092 if (map_entry
->second
== type
)
1094 *conflicting_name
= name
;
1102 bool Program::DetectVaryingsMismatch(std::string
* conflicting_name
) const {
1103 DCHECK(attached_shaders_
[0].get() &&
1104 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1105 attached_shaders_
[1].get() &&
1106 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1107 const ShaderTranslator::VariableMap
* vertex_varyings
=
1108 &(attached_shaders_
[0]->varying_map());
1109 const ShaderTranslator::VariableMap
* fragment_varyings
=
1110 &(attached_shaders_
[1]->varying_map());
1112 for (ShaderTranslator::VariableMap::const_iterator iter
=
1113 fragment_varyings
->begin();
1114 iter
!= fragment_varyings
->end(); ++iter
) {
1115 const std::string
& name
= iter
->first
;
1116 if (IsBuiltInVarying(name
))
1119 ShaderTranslator::VariableMap::const_iterator hit
=
1120 vertex_varyings
->find(name
);
1121 if (hit
== vertex_varyings
->end()) {
1122 if (iter
->second
.static_use
) {
1123 *conflicting_name
= name
;
1129 if (hit
->second
.type
!= iter
->second
.type
||
1130 hit
->second
.size
!= iter
->second
.size
) {
1131 *conflicting_name
= name
;
1139 bool Program::DetectGlobalNameConflicts(std::string
* conflicting_name
) const {
1140 DCHECK(attached_shaders_
[0].get() &&
1141 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1142 attached_shaders_
[1].get() &&
1143 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1144 const ShaderTranslator::VariableMap
* uniforms
[2];
1145 uniforms
[0] = &(attached_shaders_
[0]->uniform_map());
1146 uniforms
[1] = &(attached_shaders_
[1]->uniform_map());
1147 const ShaderTranslator::VariableMap
* attribs
=
1148 &(attached_shaders_
[0]->attrib_map());
1150 for (ShaderTranslator::VariableMap::const_iterator iter
=
1151 attribs
->begin(); iter
!= attribs
->end(); ++iter
) {
1152 for (int ii
= 0; ii
< 2; ++ii
) {
1153 if (uniforms
[ii
]->find(iter
->first
) != uniforms
[ii
]->end()) {
1154 *conflicting_name
= iter
->first
;
1162 bool Program::CheckVaryingsPacking(
1163 Program::VaryingsPackingOption option
) const {
1164 DCHECK(attached_shaders_
[0].get() &&
1165 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1166 attached_shaders_
[1].get() &&
1167 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1168 const ShaderTranslator::VariableMap
* vertex_varyings
=
1169 &(attached_shaders_
[0]->varying_map());
1170 const ShaderTranslator::VariableMap
* fragment_varyings
=
1171 &(attached_shaders_
[1]->varying_map());
1173 std::map
<std::string
, ShVariableInfo
> combined_map
;
1175 for (ShaderTranslator::VariableMap::const_iterator iter
=
1176 fragment_varyings
->begin();
1177 iter
!= fragment_varyings
->end(); ++iter
) {
1178 if (!iter
->second
.static_use
&& option
== kCountOnlyStaticallyUsed
)
1180 if (!IsBuiltInVarying(iter
->first
)) {
1181 ShaderTranslator::VariableMap::const_iterator vertex_iter
=
1182 vertex_varyings
->find(iter
->first
);
1183 if (vertex_iter
== vertex_varyings
->end() ||
1184 (!vertex_iter
->second
.static_use
&&
1185 option
== kCountOnlyStaticallyUsed
))
1190 #if (ANGLE_SH_VERSION >= 126)
1191 var
.type
= static_cast<sh::GLenum
>(iter
->second
.type
);
1193 var
.type
= static_cast<ShDataType
>(iter
->second
.type
);
1195 var
.size
= iter
->second
.size
;
1196 combined_map
[iter
->first
] = var
;
1199 if (combined_map
.size() == 0)
1201 scoped_ptr
<ShVariableInfo
[]> variables(
1202 new ShVariableInfo
[combined_map
.size()]);
1204 for (std::map
<std::string
, ShVariableInfo
>::const_iterator iter
=
1205 combined_map
.begin();
1206 iter
!= combined_map
.end(); ++iter
) {
1207 variables
[index
].type
= iter
->second
.type
;
1208 variables
[index
].size
= iter
->second
.size
;
1211 return ShCheckVariablesWithinPackingLimits(
1212 static_cast<int>(manager_
->max_varying_vectors()),
1214 combined_map
.size()) == 1;
1217 static uint32
ComputeOffset(const void* start
, const void* position
) {
1218 return static_cast<const uint8
*>(position
) -
1219 static_cast<const uint8
*>(start
);
1222 void Program::GetProgramInfo(
1223 ProgramManager
* manager
, CommonDecoder::Bucket
* bucket
) const {
1224 // NOTE: It seems to me the math in here does not need check for overflow
1225 // because the data being calucated from has various small limits. The max
1226 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1227 // of an identifier is 256 characters.
1228 uint32 num_locations
= 0;
1229 uint32 total_string_size
= 0;
1231 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
1232 const VertexAttrib
& info
= attrib_infos_
[ii
];
1234 total_string_size
+= info
.name
.size();
1237 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
1238 const UniformInfo
& info
= uniform_infos_
[ii
];
1239 if (info
.IsValid()) {
1240 num_locations
+= info
.element_locations
.size();
1241 total_string_size
+= info
.name
.size();
1245 uint32 num_inputs
= attrib_infos_
.size() + num_uniforms_
;
1246 uint32 input_size
= num_inputs
* sizeof(ProgramInput
);
1247 uint32 location_size
= num_locations
* sizeof(int32
);
1248 uint32 size
= sizeof(ProgramInfoHeader
) +
1249 input_size
+ location_size
+ total_string_size
;
1251 bucket
->SetSize(size
);
1252 ProgramInfoHeader
* header
= bucket
->GetDataAs
<ProgramInfoHeader
*>(0, size
);
1253 ProgramInput
* inputs
= bucket
->GetDataAs
<ProgramInput
*>(
1254 sizeof(ProgramInfoHeader
), input_size
);
1255 int32
* locations
= bucket
->GetDataAs
<int32
*>(
1256 sizeof(ProgramInfoHeader
) + input_size
, location_size
);
1257 char* strings
= bucket
->GetDataAs
<char*>(
1258 sizeof(ProgramInfoHeader
) + input_size
+ location_size
,
1265 header
->link_status
= link_status_
;
1266 header
->num_attribs
= attrib_infos_
.size();
1267 header
->num_uniforms
= num_uniforms_
;
1269 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
1270 const VertexAttrib
& info
= attrib_infos_
[ii
];
1271 inputs
->size
= info
.size
;
1272 inputs
->type
= info
.type
;
1273 inputs
->location_offset
= ComputeOffset(header
, locations
);
1274 inputs
->name_offset
= ComputeOffset(header
, strings
);
1275 inputs
->name_length
= info
.name
.size();
1276 *locations
++ = info
.location
;
1277 memcpy(strings
, info
.name
.c_str(), info
.name
.size());
1278 strings
+= info
.name
.size();
1282 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
1283 const UniformInfo
& info
= uniform_infos_
[ii
];
1284 if (info
.IsValid()) {
1285 inputs
->size
= info
.size
;
1286 inputs
->type
= info
.type
;
1287 inputs
->location_offset
= ComputeOffset(header
, locations
);
1288 inputs
->name_offset
= ComputeOffset(header
, strings
);
1289 inputs
->name_length
= info
.name
.size();
1290 DCHECK(static_cast<size_t>(info
.size
) == info
.element_locations
.size());
1291 for (size_t jj
= 0; jj
< info
.element_locations
.size(); ++jj
) {
1292 if (info
.element_locations
[jj
] == -1)
1295 *locations
++ = ProgramManager::MakeFakeLocation(ii
, jj
);
1297 memcpy(strings
, info
.name
.c_str(), info
.name
.size());
1298 strings
+= info
.name
.size();
1303 DCHECK_EQ(ComputeOffset(header
, strings
), size
);
1306 Program::~Program() {
1308 if (manager_
->have_context_
) {
1309 glDeleteProgram(service_id());
1311 manager_
->StopTracking(this);
1317 ProgramManager::ProgramManager(ProgramCache
* program_cache
,
1318 uint32 max_varying_vectors
)
1319 : program_count_(0),
1320 have_context_(true),
1321 program_cache_(program_cache
),
1322 max_varying_vectors_(max_varying_vectors
) { }
1324 ProgramManager::~ProgramManager() {
1325 DCHECK(programs_
.empty());
1328 void ProgramManager::Destroy(bool have_context
) {
1329 have_context_
= have_context
;
1333 void ProgramManager::StartTracking(Program
* /* program */) {
1337 void ProgramManager::StopTracking(Program
* /* program */) {
1341 Program
* ProgramManager::CreateProgram(
1342 GLuint client_id
, GLuint service_id
) {
1343 std::pair
<ProgramMap::iterator
, bool> result
=
1345 std::make_pair(client_id
,
1346 scoped_refptr
<Program
>(
1347 new Program(this, service_id
))));
1348 DCHECK(result
.second
);
1349 return result
.first
->second
.get();
1352 Program
* ProgramManager::GetProgram(GLuint client_id
) {
1353 ProgramMap::iterator it
= programs_
.find(client_id
);
1354 return it
!= programs_
.end() ? it
->second
.get() : NULL
;
1357 bool ProgramManager::GetClientId(GLuint service_id
, GLuint
* client_id
) const {
1358 // This doesn't need to be fast. It's only used during slow queries.
1359 for (ProgramMap::const_iterator it
= programs_
.begin();
1360 it
!= programs_
.end(); ++it
) {
1361 if (it
->second
->service_id() == service_id
) {
1362 *client_id
= it
->first
;
1369 ProgramCache
* ProgramManager::program_cache() const {
1370 return program_cache_
;
1373 bool ProgramManager::IsOwned(Program
* program
) {
1374 for (ProgramMap::iterator it
= programs_
.begin();
1375 it
!= programs_
.end(); ++it
) {
1376 if (it
->second
.get() == program
) {
1383 void ProgramManager::RemoveProgramInfoIfUnused(
1384 ShaderManager
* shader_manager
, Program
* program
) {
1385 DCHECK(shader_manager
);
1387 DCHECK(IsOwned(program
));
1388 if (program
->IsDeleted() && !program
->InUse()) {
1389 program
->DetachShaders(shader_manager
);
1390 for (ProgramMap::iterator it
= programs_
.begin();
1391 it
!= programs_
.end(); ++it
) {
1392 if (it
->second
.get() == program
) {
1393 programs_
.erase(it
);
1401 void ProgramManager::MarkAsDeleted(
1402 ShaderManager
* shader_manager
,
1404 DCHECK(shader_manager
);
1406 DCHECK(IsOwned(program
));
1407 program
->MarkAsDeleted();
1408 RemoveProgramInfoIfUnused(shader_manager
, program
);
1411 void ProgramManager::UseProgram(Program
* program
) {
1413 DCHECK(IsOwned(program
));
1414 program
->IncUseCount();
1417 void ProgramManager::UnuseProgram(
1418 ShaderManager
* shader_manager
,
1420 DCHECK(shader_manager
);
1422 DCHECK(IsOwned(program
));
1423 program
->DecUseCount();
1424 RemoveProgramInfoIfUnused(shader_manager
, program
);
1427 void ProgramManager::ClearUniforms(Program
* program
) {
1429 program
->ClearUniforms(&zero_
);
1432 int32
ProgramManager::MakeFakeLocation(int32 index
, int32 element
) {
1433 return index
+ element
* 0x10000;
1436 } // namespace gles2