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
;
147 case GL_UNSIGNED_INT
:
148 accepts_api_type
= kUniform1ui
;
150 case GL_UNSIGNED_INT_VEC2
:
151 accepts_api_type
= kUniform2ui
;
153 case GL_UNSIGNED_INT_VEC3
:
154 accepts_api_type
= kUniform3ui
;
156 case GL_UNSIGNED_INT_VEC4
:
157 accepts_api_type
= kUniform4ui
;
161 accepts_api_type
= kUniform1i
| kUniform1ui
| kUniform1f
;
164 accepts_api_type
= kUniform2i
| kUniform2ui
| kUniform2f
;
167 accepts_api_type
= kUniform3i
| kUniform3ui
| kUniform3f
;
170 accepts_api_type
= kUniform4i
| kUniform4ui
| kUniform4f
;
174 accepts_api_type
= kUniform1f
;
177 accepts_api_type
= kUniform2f
;
180 accepts_api_type
= kUniform3f
;
183 accepts_api_type
= kUniform4f
;
187 accepts_api_type
= kUniformMatrix2f
;
190 accepts_api_type
= kUniformMatrix3f
;
193 accepts_api_type
= kUniformMatrix4f
;
196 case GL_FLOAT_MAT2x3
:
197 accepts_api_type
= kUniformMatrix2x3f
;
199 case GL_FLOAT_MAT2x4
:
200 accepts_api_type
= kUniformMatrix2x4f
;
202 case GL_FLOAT_MAT3x2
:
203 accepts_api_type
= kUniformMatrix3x2f
;
205 case GL_FLOAT_MAT3x4
:
206 accepts_api_type
= kUniformMatrix3x4f
;
208 case GL_FLOAT_MAT4x2
:
209 accepts_api_type
= kUniformMatrix4x2f
;
211 case GL_FLOAT_MAT4x3
:
212 accepts_api_type
= kUniformMatrix4x3f
;
216 case GL_SAMPLER_2D_RECT_ARB
:
217 case GL_SAMPLER_CUBE
:
218 case GL_SAMPLER_3D_OES
:
219 case GL_SAMPLER_EXTERNAL_OES
:
220 case GL_SAMPLER_2D_ARRAY
:
221 case GL_SAMPLER_2D_SHADOW
:
222 case GL_SAMPLER_2D_ARRAY_SHADOW
:
223 case GL_INT_SAMPLER_2D
:
224 case GL_INT_SAMPLER_3D
:
225 case GL_INT_SAMPLER_CUBE
:
226 case GL_INT_SAMPLER_2D_ARRAY
:
227 case GL_UNSIGNED_INT_SAMPLER_2D
:
228 case GL_UNSIGNED_INT_SAMPLER_3D
:
229 case GL_UNSIGNED_INT_SAMPLER_CUBE
:
230 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY
:
231 accepts_api_type
= kUniform1i
;
235 NOTREACHED() << "Unhandled UniformInfo type " << type
;
240 Program::UniformInfo::~UniformInfo() {}
242 bool ProgramManager::IsInvalidPrefix(const char* name
, size_t length
) {
243 static const char kInvalidPrefix
[] = { 'g', 'l', '_' };
244 return (length
>= sizeof(kInvalidPrefix
) &&
245 memcmp(name
, kInvalidPrefix
, sizeof(kInvalidPrefix
)) == 0);
248 Program::Program(ProgramManager
* manager
, GLuint service_id
)
251 max_attrib_name_length_(0),
252 max_uniform_name_length_(0),
253 service_id_(service_id
),
257 uniforms_cleared_(false),
259 transform_feedback_buffer_mode_(GL_NONE
) {
260 manager_
->StartTracking(this);
263 void Program::Reset() {
265 link_status_
= false;
267 max_uniform_name_length_
= 0;
268 max_attrib_name_length_
= 0;
269 attrib_infos_
.clear();
270 uniform_infos_
.clear();
271 sampler_indices_
.clear();
272 attrib_location_to_index_map_
.clear();
275 std::string
Program::ProcessLogInfo(
276 const std::string
& log
) {
278 re2::StringPiece
input(log
);
279 std::string prior_log
;
280 std::string hashed_name
;
281 while (RE2::Consume(&input
,
282 "(.*?)(webgl_[0123456789abcdefABCDEF]+)",
287 const std::string
* original_name
=
288 GetOriginalNameFromHashedName(hashed_name
);
290 output
+= *original_name
;
292 output
+= hashed_name
;
295 return output
+ input
.as_string();
298 void Program::UpdateLogInfo() {
300 glGetProgramiv(service_id_
, GL_INFO_LOG_LENGTH
, &max_len
);
305 scoped_ptr
<char[]> temp(new char[max_len
]);
307 glGetProgramInfoLog(service_id_
, max_len
, &len
, temp
.get());
308 DCHECK(max_len
== 0 || len
< max_len
);
309 DCHECK(len
== 0 || temp
[len
] == '\0');
310 std::string
log(temp
.get(), len
);
311 set_log_info(ProcessLogInfo(log
).c_str());
314 void Program::ClearUniforms(
315 std::vector
<uint8
>* zero_buffer
) {
317 if (uniforms_cleared_
) {
320 uniforms_cleared_
= true;
321 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
322 const UniformInfo
& uniform_info
= uniform_infos_
[ii
];
323 if (!uniform_info
.IsValid()) {
326 GLint location
= uniform_info
.element_locations
[0];
327 GLsizei size
= uniform_info
.size
;
329 GLES2Util::GetElementCountForUniformType(uniform_info
.type
) *
330 GLES2Util::GetElementSizeForUniformType(uniform_info
.type
);
331 DCHECK_LT(0u, unit_size
);
332 uint32 size_needed
= size
* unit_size
;
333 if (size_needed
> zero_buffer
->size()) {
334 zero_buffer
->resize(size_needed
, 0u);
336 const void* zero
= &(*zero_buffer
)[0];
337 switch (uniform_info
.type
) {
339 glUniform1fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
342 glUniform2fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
345 glUniform3fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
348 glUniform4fv(location
, size
, reinterpret_cast<const GLfloat
*>(zero
));
353 case GL_SAMPLER_CUBE
:
354 case GL_SAMPLER_EXTERNAL_OES
: // extension.
355 case GL_SAMPLER_2D_RECT_ARB
: // extension.
356 glUniform1iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
360 glUniform2iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
364 glUniform3iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
368 glUniform4iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
372 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
376 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
380 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
384 case GL_UNSIGNED_INT
:
385 glUniform1uiv(location
, size
, reinterpret_cast<const GLuint
*>(zero
));
388 case GL_SAMPLER_2D_SHADOW
:
389 case GL_SAMPLER_2D_ARRAY
:
390 case GL_SAMPLER_2D_ARRAY_SHADOW
:
391 case GL_SAMPLER_CUBE_SHADOW
:
392 case GL_INT_SAMPLER_2D
:
393 case GL_INT_SAMPLER_3D
:
394 case GL_INT_SAMPLER_CUBE
:
395 case GL_INT_SAMPLER_2D_ARRAY
:
396 case GL_UNSIGNED_INT_SAMPLER_2D
:
397 case GL_UNSIGNED_INT_SAMPLER_3D
:
398 case GL_UNSIGNED_INT_SAMPLER_CUBE
:
399 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY
:
400 glUniform1iv(location
, size
, reinterpret_cast<const GLint
*>(zero
));
402 case GL_UNSIGNED_INT_VEC2
:
403 glUniform2uiv(location
, size
, reinterpret_cast<const GLuint
*>(zero
));
405 case GL_UNSIGNED_INT_VEC3
:
406 glUniform3uiv(location
, size
, reinterpret_cast<const GLuint
*>(zero
));
408 case GL_UNSIGNED_INT_VEC4
:
409 glUniform4uiv(location
, size
, reinterpret_cast<const GLuint
*>(zero
));
411 case GL_FLOAT_MAT2x3
:
412 glUniformMatrix2x3fv(
413 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
415 case GL_FLOAT_MAT3x2
:
416 glUniformMatrix3x2fv(
417 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
419 case GL_FLOAT_MAT2x4
:
420 glUniformMatrix2x4fv(
421 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
423 case GL_FLOAT_MAT4x2
:
424 glUniformMatrix4x2fv(
425 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
427 case GL_FLOAT_MAT3x4
:
428 glUniformMatrix3x4fv(
429 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
431 case GL_FLOAT_MAT4x3
:
432 glUniformMatrix4x3fv(
433 location
, size
, false, reinterpret_cast<const GLfloat
*>(zero
));
446 UniformData() : size(-1), type(GL_NONE
), location(0), added(false) {
448 std::string queried_name
;
449 std::string corrected_name
;
450 std::string original_name
;
457 struct UniformDataComparer
{
458 bool operator()(const UniformData
& lhs
, const UniformData
& rhs
) const {
459 return lhs
.queried_name
< rhs
.queried_name
;
463 } // anonymous namespace
465 void Program::Update() {
469 uniforms_cleared_
= false;
470 GLint num_attribs
= 0;
472 GLint max_location
= -1;
473 glGetProgramiv(service_id_
, GL_ACTIVE_ATTRIBUTES
, &num_attribs
);
474 glGetProgramiv(service_id_
, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
, &max_len
);
475 // TODO(gman): Should we check for error?
476 scoped_ptr
<char[]> name_buffer(new char[max_len
]);
477 for (GLint ii
= 0; ii
< num_attribs
; ++ii
) {
482 service_id_
, ii
, max_len
, &length
, &size
, &type
, name_buffer
.get());
483 DCHECK(max_len
== 0 || length
< max_len
);
484 DCHECK(length
== 0 || name_buffer
[length
] == '\0');
485 std::string original_name
;
486 GetVertexAttribData(name_buffer
.get(), &original_name
, &type
);
487 // TODO(gman): Should we check for error?
488 GLint location
= glGetAttribLocation(service_id_
, name_buffer
.get());
489 if (location
> max_location
) {
490 max_location
= location
;
492 attrib_infos_
.push_back(VertexAttrib(1, type
, original_name
, location
));
493 max_attrib_name_length_
= std::max(
494 max_attrib_name_length_
, static_cast<GLsizei
>(original_name
.size()));
497 // Create attrib location to index map.
498 attrib_location_to_index_map_
.resize(max_location
+ 1);
499 for (GLint ii
= 0; ii
<= max_location
; ++ii
) {
500 attrib_location_to_index_map_
[ii
] = -1;
502 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
503 const VertexAttrib
& info
= attrib_infos_
[ii
];
504 attrib_location_to_index_map_
[info
.location
] = ii
;
508 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
509 switches::kEnableGPUServiceLoggingGPU
)) {
510 DVLOG(1) << "----: attribs for service_id: " << service_id();
511 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
512 const VertexAttrib
& info
= attrib_infos_
[ii
];
513 DVLOG(1) << ii
<< ": loc = " << info
.location
514 << ", size = " << info
.size
515 << ", type = " << GLES2Util::GetStringEnum(info
.type
)
516 << ", name = " << info
.name
;
522 GLint num_uniforms
= 0;
523 glGetProgramiv(service_id_
, GL_ACTIVE_UNIFORMS
, &num_uniforms
);
524 glGetProgramiv(service_id_
, GL_ACTIVE_UNIFORM_MAX_LENGTH
, &max_len
);
525 name_buffer
.reset(new char[max_len
]);
527 // Reads all the names.
528 std::vector
<UniformData
> uniform_data
;
529 for (GLint ii
= 0; ii
< num_uniforms
; ++ii
) {
533 service_id_
, ii
, max_len
, &length
,
534 &data
.size
, &data
.type
, name_buffer
.get());
535 DCHECK(max_len
== 0 || length
< max_len
);
536 DCHECK(length
== 0 || name_buffer
[length
] == '\0');
537 data
.queried_name
= std::string(name_buffer
.get());
538 GetCorrectedUniformData(data
.queried_name
, &data
.corrected_name
,
539 &data
.original_name
, &data
.size
, &data
.type
);
540 uniform_data
.push_back(data
);
543 // NOTE: We don't care if 2 uniforms are bound to the same location.
544 // One of them will take preference. The spec allows this, same as
545 // BindAttribLocation.
547 // The reason we don't check is if we were to fail we'd have to
548 // restore the previous program but since we've already linked successfully
549 // at this point the previous program is gone.
551 // Assigns the uniforms with bindings.
552 size_t next_available_index
= 0;
553 for (size_t ii
= 0; ii
< uniform_data
.size(); ++ii
) {
554 UniformData
& data
= uniform_data
[ii
];
555 // Force builtin uniforms (gl_DepthRange) to have invalid location.
556 if (ProgramManager::IsInvalidPrefix(data
.queried_name
.c_str(),
557 data
.queried_name
.size())) {
561 glGetUniformLocation(service_id_
, data
.queried_name
.c_str());
564 std::string short_name
;
565 int element_index
= 0;
566 bool good
= GetUniformNameSansElement(data
.queried_name
, &element_index
,
569 LocationMap::const_iterator it
= bind_uniform_location_map_
.find(
571 if (it
!= bind_uniform_location_map_
.end()) {
573 data
.size
, data
.type
, data
.location
, it
->second
, data
.corrected_name
,
574 data
.original_name
, &next_available_index
);
579 // Assigns the uniforms that were not bound.
580 for (size_t ii
= 0; ii
< uniform_data
.size(); ++ii
) {
581 const UniformData
& data
= uniform_data
[ii
];
584 data
.size
, data
.type
, data
.location
, -1, data
.corrected_name
,
585 data
.original_name
, &next_available_index
);
590 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
591 switches::kEnableGPUServiceLoggingGPU
)) {
592 DVLOG(1) << "----: uniforms for service_id: " << service_id();
593 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
594 const UniformInfo
& info
= uniform_infos_
[ii
];
595 if (info
.IsValid()) {
596 DVLOG(1) << ii
<< ": loc = " << info
.element_locations
[0]
597 << ", size = " << info
.size
598 << ", type = " << GLES2Util::GetStringEnum(info
.type
)
599 << ", name = " << info
.name
;
608 void Program::ExecuteBindAttribLocationCalls() {
609 for (const auto& key_value
: bind_attrib_location_map_
) {
610 const std::string
* mapped_name
= GetAttribMappedName(key_value
.first
);
612 glBindAttribLocation(service_id_
, key_value
.second
, mapped_name
->c_str());
616 bool Program::ExecuteTransformFeedbackVaryingsCall() {
617 if (!transform_feedback_varyings_
.empty()) {
618 Shader
* vertex_shader
= attached_shaders_
[0].get();
619 if (!vertex_shader
) {
620 set_log_info("TransformFeedbackVaryings: missing vertex shader");
624 std::vector
<const char*> mapped_names
;
625 mapped_names
.reserve(transform_feedback_varyings_
.size());
626 for (StringVector::const_iterator it
=
627 transform_feedback_varyings_
.begin();
628 it
!= transform_feedback_varyings_
.end(); ++it
) {
629 const std::string
& orig
= *it
;
630 const std::string
* mapped
= vertex_shader
->GetVaryingMappedName(orig
);
632 std::string log
= "TransformFeedbackVaryings: no varying named " + orig
;
633 set_log_info(log
.c_str());
636 mapped_names
.push_back(mapped
->c_str());
638 glTransformFeedbackVaryings(service_id_
,
640 &mapped_names
.front(),
641 transform_feedback_buffer_mode_
);
647 bool Program::Link(ShaderManager
* manager
,
648 Program::VaryingsPackingOption varyings_packing_option
,
649 const ShaderCacheCallback
& shader_callback
) {
652 if (!AttachedShadersExist()) {
653 set_log_info("missing shaders");
657 TimeTicks before_time
= TimeTicks::Now();
659 ProgramCache
* cache
= manager_
->program_cache_
;
661 DCHECK(!attached_shaders_
[0]->last_compiled_source().empty() &&
662 !attached_shaders_
[1]->last_compiled_source().empty());
663 ProgramCache::LinkedProgramStatus status
= cache
->GetLinkedProgramStatus(
664 attached_shaders_
[0]->last_compiled_signature(),
665 attached_shaders_
[1]->last_compiled_signature(),
666 &bind_attrib_location_map_
,
667 transform_feedback_varyings_
,
668 transform_feedback_buffer_mode_
);
670 bool cache_hit
= status
== ProgramCache::LINK_SUCCEEDED
;
671 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.CacheHit", cache_hit
);
674 ProgramCache::ProgramLoadResult success
=
675 cache
->LoadLinkedProgram(service_id(),
676 attached_shaders_
[0].get(),
677 attached_shaders_
[1].get(),
678 &bind_attrib_location_map_
,
679 transform_feedback_varyings_
,
680 transform_feedback_buffer_mode_
,
682 link
= success
!= ProgramCache::PROGRAM_LOAD_SUCCESS
;
683 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link
);
688 CompileAttachedShaders();
691 set_log_info("invalid shaders");
694 if (DetectShaderVersionMismatch()) {
695 set_log_info("Versions of linked shaders have to match.");
698 if (DetectAttribLocationBindingConflicts()) {
699 set_log_info("glBindAttribLocation() conflicts");
702 std::string conflicting_name
;
703 if (DetectUniformsMismatch(&conflicting_name
)) {
704 std::string info_log
= "Uniforms with the same name but different "
705 "type/precision: " + conflicting_name
;
706 set_log_info(ProcessLogInfo(info_log
).c_str());
709 if (DetectUniformLocationBindingConflicts()) {
710 set_log_info("glBindUniformLocationCHROMIUM() conflicts");
713 if (DetectVaryingsMismatch(&conflicting_name
)) {
714 std::string info_log
= "Varyings with the same name but different type, "
715 "or statically used varyings in fragment shader "
716 "are not declared in vertex shader: " +
718 set_log_info(ProcessLogInfo(info_log
).c_str());
721 if (DetectBuiltInInvariantConflicts()) {
722 set_log_info("Invariant settings for certain built-in varyings "
726 if (DetectGlobalNameConflicts(&conflicting_name
)) {
727 std::string info_log
= "Name conflicts between an uniform and an "
728 "attribute: " + conflicting_name
;
729 set_log_info(ProcessLogInfo(info_log
).c_str());
732 if (!CheckVaryingsPacking(varyings_packing_option
)) {
733 set_log_info("Varyings over maximum register limit");
737 ExecuteBindAttribLocationCalls();
738 if (!ExecuteTransformFeedbackVaryingsCall()) {
741 before_time
= TimeTicks::Now();
742 if (cache
&& gfx::g_driver_gl
.ext
.b_GL_ARB_get_program_binary
) {
743 glProgramParameteri(service_id(),
744 PROGRAM_BINARY_RETRIEVABLE_HINT
,
747 glLinkProgram(service_id());
751 glGetProgramiv(service_id(), GL_LINK_STATUS
, &success
);
752 if (success
== GL_TRUE
) {
756 cache
->SaveLinkedProgram(service_id(),
757 attached_shaders_
[0].get(),
758 attached_shaders_
[1].get(),
759 &bind_attrib_location_map_
,
760 transform_feedback_varyings_
,
761 transform_feedback_buffer_mode_
,
764 UMA_HISTOGRAM_CUSTOM_COUNTS(
765 "GPU.ProgramCache.BinaryCacheMissTime",
766 static_cast<base::HistogramBase::Sample
>(
767 (TimeTicks::Now() - before_time
).InMicroseconds()),
769 static_cast<base::HistogramBase::Sample
>(
770 TimeDelta::FromSeconds(10).InMicroseconds()),
773 UMA_HISTOGRAM_CUSTOM_COUNTS(
774 "GPU.ProgramCache.BinaryCacheHitTime",
775 static_cast<base::HistogramBase::Sample
>(
776 (TimeTicks::Now() - before_time
).InMicroseconds()),
778 static_cast<base::HistogramBase::Sample
>(
779 TimeDelta::FromSeconds(1).InMicroseconds()),
785 return success
== GL_TRUE
;
788 void Program::Validate() {
790 set_log_info("program not linked");
793 glValidateProgram(service_id());
797 GLint
Program::GetUniformFakeLocation(
798 const std::string
& name
) const {
799 bool getting_array_location
= false;
800 size_t open_pos
= std::string::npos
;
802 if (!GLES2Util::ParseUniformName(
803 name
, &open_pos
, &index
, &getting_array_location
)) {
806 for (GLuint ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
807 const UniformInfo
& info
= uniform_infos_
[ii
];
808 if (!info
.IsValid()) {
811 if (info
.name
== name
||
813 info
.name
.compare(0, info
.name
.size() - 3, name
) == 0)) {
814 return info
.fake_location_base
;
815 } else if (getting_array_location
&& info
.is_array
) {
816 // Look for an array specification.
817 size_t open_pos_2
= info
.name
.find_last_of('[');
818 if (open_pos_2
== open_pos
&&
819 name
.compare(0, open_pos
, info
.name
, 0, open_pos
) == 0) {
820 if (index
>= 0 && index
< info
.size
) {
821 DCHECK_GT(static_cast<int>(info
.element_locations
.size()), index
);
822 if (info
.element_locations
[index
] == -1)
824 return ProgramManager::MakeFakeLocation(
825 info
.fake_location_base
, index
);
833 GLint
Program::GetAttribLocation(
834 const std::string
& original_name
) const {
835 for (GLuint ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
836 const VertexAttrib
& info
= attrib_infos_
[ii
];
837 if (info
.name
== original_name
) {
838 return info
.location
;
844 const Program::UniformInfo
*
845 Program::GetUniformInfoByFakeLocation(
846 GLint fake_location
, GLint
* real_location
, GLint
* array_index
) const {
847 DCHECK(real_location
);
849 if (fake_location
< 0) {
853 GLint uniform_index
= GetUniformInfoIndexFromFakeLocation(fake_location
);
854 if (uniform_index
>= 0 &&
855 static_cast<size_t>(uniform_index
) < uniform_infos_
.size()) {
856 const UniformInfo
& uniform_info
= uniform_infos_
[uniform_index
];
857 if (!uniform_info
.IsValid()) {
860 GLint element_index
= GetArrayElementIndexFromFakeLocation(fake_location
);
861 if (element_index
< uniform_info
.size
) {
862 *real_location
= uniform_info
.element_locations
[element_index
];
863 *array_index
= element_index
;
864 return &uniform_info
;
870 const std::string
* Program::GetAttribMappedName(
871 const std::string
& original_name
) const {
872 for (auto shader
: attached_shaders_
) {
874 const std::string
* mapped_name
=
875 shader
->GetAttribMappedName(original_name
);
883 const std::string
* Program::GetUniformMappedName(
884 const std::string
& original_name
) const {
885 for (auto shader
: attached_shaders_
) {
887 const std::string
* mapped_name
=
888 shader
->GetUniformMappedName(original_name
);
896 const std::string
* Program::GetOriginalNameFromHashedName(
897 const std::string
& hashed_name
) const {
898 for (auto shader
: attached_shaders_
) {
900 const std::string
* original_name
=
901 shader
->GetOriginalNameFromHashedName(hashed_name
);
903 return original_name
;
909 bool Program::SetUniformLocationBinding(
910 const std::string
& name
, GLint location
) {
911 std::string short_name
;
912 int element_index
= 0;
913 if (!GetUniformNameSansElement(name
, &element_index
, &short_name
) ||
914 element_index
!= 0) {
917 bind_uniform_location_map_
[short_name
] = location
;
921 // Note: This is only valid to call right after a program has been linked
923 void Program::GetCorrectedUniformData(
924 const std::string
& name
,
925 std::string
* corrected_name
, std::string
* original_name
,
926 GLsizei
* size
, GLenum
* type
) const {
927 DCHECK(corrected_name
&& original_name
&& size
&& type
);
928 for (auto shader
: attached_shaders_
) {
931 const sh::ShaderVariable
* info
= NULL
;
932 const sh::Uniform
* uniform
= shader
->GetUniformInfo(name
);
935 found
= uniform
->findInfoByMappedName(name
, &info
, original_name
);
937 const std::string
kArraySpec("[0]");
938 if (info
->arraySize
> 0 &&
939 !base::EndsWith(name
, kArraySpec
, base::CompareCase::SENSITIVE
)) {
940 *corrected_name
= name
+ kArraySpec
;
941 *original_name
+= kArraySpec
;
943 *corrected_name
= name
;
946 *size
= std::max(1u, info
->arraySize
);
950 // TODO(zmo): this path should never be reached unless there is a serious
951 // bug in the driver or in ANGLE translator.
952 *corrected_name
= name
;
953 *original_name
= name
;
956 void Program::GetVertexAttribData(
957 const std::string
& name
, std::string
* original_name
, GLenum
* type
) const {
958 DCHECK(original_name
);
960 Shader
* shader
= attached_shaders_
[ShaderTypeToIndex(GL_VERTEX_SHADER
)].get();
962 // Vertex attributes can not be arrays or structs (GLSL ES 3.00.4, section
963 // 4.3.4, "Input Variables"), so the top level sh::Attribute returns the
964 // information we need.
965 const sh::Attribute
* info
= shader
->GetAttribInfo(name
);
967 *original_name
= info
->name
;
972 // TODO(zmo): this path should never be reached unless there is a serious
973 // bug in the driver or in ANGLE translator.
974 *original_name
= name
;
977 void Program::AddUniformInfo(
978 GLsizei size
, GLenum type
, GLint location
, GLint fake_base_location
,
979 const std::string
& name
, const std::string
& original_name
,
980 size_t* next_available_index
) {
981 DCHECK(next_available_index
);
982 const char* kArraySpec
= "[0]";
983 size_t uniform_index
=
984 fake_base_location
>= 0 ? fake_base_location
: *next_available_index
;
985 if (uniform_infos_
.size() < uniform_index
+ 1) {
986 uniform_infos_
.resize(uniform_index
+ 1);
989 // Before linking, we already validated that no two statically used uniforms
990 // are bound to the same location.
991 DCHECK(!uniform_infos_
[uniform_index
].IsValid());
993 uniform_infos_
[uniform_index
] = UniformInfo(
994 size
, type
, uniform_index
, original_name
);
997 UniformInfo
& info
= uniform_infos_
[uniform_index
];
998 info
.element_locations
.resize(size
);
999 info
.element_locations
[0] = location
;
1001 size_t num_texture_units
= info
.IsSampler() ? static_cast<size_t>(size
) : 0u;
1002 info
.texture_units
.clear();
1003 info
.texture_units
.resize(num_texture_units
, 0);
1006 // Go through the array element locations looking for a match.
1007 // We can skip the first element because it's the same as the
1008 // the location without the array operators.
1009 size_t array_pos
= name
.rfind(kArraySpec
);
1010 std::string base_name
= name
;
1011 if (name
.size() > 3) {
1012 if (array_pos
!= name
.size() - 3) {
1013 info
.name
= name
+ kArraySpec
;
1015 base_name
= name
.substr(0, name
.size() - 3);
1018 for (GLsizei ii
= 1; ii
< info
.size
; ++ii
) {
1019 std::string
element_name(base_name
+ "[" + base::IntToString(ii
) + "]");
1020 info
.element_locations
[ii
] =
1021 glGetUniformLocation(service_id_
, element_name
.c_str());
1027 (info
.name
.size() > 3 &&
1028 info
.name
.rfind(kArraySpec
) == info
.name
.size() - 3));
1030 if (info
.IsSampler()) {
1031 sampler_indices_
.push_back(info
.fake_location_base
);
1033 max_uniform_name_length_
=
1034 std::max(max_uniform_name_length_
,
1035 static_cast<GLsizei
>(info
.name
.size()));
1037 while (*next_available_index
< uniform_infos_
.size() &&
1038 uniform_infos_
[*next_available_index
].IsValid()) {
1039 *next_available_index
= *next_available_index
+ 1;
1043 const Program::UniformInfo
*
1044 Program::GetUniformInfo(
1045 GLint index
) const {
1046 if (static_cast<size_t>(index
) >= uniform_infos_
.size()) {
1050 const UniformInfo
& info
= uniform_infos_
[index
];
1051 return info
.IsValid() ? &info
: NULL
;
1054 bool Program::SetSamplers(
1055 GLint num_texture_units
, GLint fake_location
,
1056 GLsizei count
, const GLint
* value
) {
1057 if (fake_location
< 0) {
1060 GLint uniform_index
= GetUniformInfoIndexFromFakeLocation(fake_location
);
1061 if (uniform_index
>= 0 &&
1062 static_cast<size_t>(uniform_index
) < uniform_infos_
.size()) {
1063 UniformInfo
& info
= uniform_infos_
[uniform_index
];
1064 if (!info
.IsValid()) {
1067 GLint element_index
= GetArrayElementIndexFromFakeLocation(fake_location
);
1068 if (element_index
< info
.size
) {
1069 count
= std::min(info
.size
- element_index
, count
);
1070 if (info
.IsSampler() && count
> 0) {
1071 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1072 if (value
[ii
] < 0 || value
[ii
] >= num_texture_units
) {
1076 std::copy(value
, value
+ count
,
1077 info
.texture_units
.begin() + element_index
);
1085 void Program::GetProgramiv(GLenum pname
, GLint
* params
) {
1087 case GL_ACTIVE_ATTRIBUTES
:
1088 *params
= attrib_infos_
.size();
1090 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
:
1091 // Notice +1 to accomodate NULL terminator.
1092 *params
= max_attrib_name_length_
+ 1;
1094 case GL_ACTIVE_UNIFORMS
:
1095 *params
= num_uniforms_
;
1097 case GL_ACTIVE_UNIFORM_MAX_LENGTH
:
1098 // Notice +1 to accomodate NULL terminator.
1099 *params
= max_uniform_name_length_
+ 1;
1101 case GL_LINK_STATUS
:
1102 *params
= link_status_
;
1104 case GL_INFO_LOG_LENGTH
:
1105 // Notice +1 to accomodate NULL terminator.
1106 *params
= log_info_
.get() ? (log_info_
->size() + 1) : 0;
1108 case GL_DELETE_STATUS
:
1111 case GL_VALIDATE_STATUS
:
1115 glGetProgramiv(service_id_
, pname
, params
);
1119 glGetProgramiv(service_id_
, pname
, params
);
1124 bool Program::AttachShader(
1125 ShaderManager
* shader_manager
,
1127 DCHECK(shader_manager
);
1129 int index
= ShaderTypeToIndex(shader
->shader_type());
1130 if (attached_shaders_
[index
].get() != NULL
) {
1133 attached_shaders_
[index
] = scoped_refptr
<Shader
>(shader
);
1134 shader_manager
->UseShader(shader
);
1138 bool Program::DetachShader(
1139 ShaderManager
* shader_manager
,
1141 DCHECK(shader_manager
);
1143 if (attached_shaders_
[ShaderTypeToIndex(shader
->shader_type())].get() !=
1147 attached_shaders_
[ShaderTypeToIndex(shader
->shader_type())] = NULL
;
1148 shader_manager
->UnuseShader(shader
);
1152 void Program::DetachShaders(ShaderManager
* shader_manager
) {
1153 DCHECK(shader_manager
);
1154 for (auto shader
: attached_shaders_
) {
1156 DetachShader(shader_manager
, shader
.get());
1161 void Program::CompileAttachedShaders() {
1162 for (auto shader
: attached_shaders_
) {
1164 shader
->DoCompile();
1169 bool Program::AttachedShadersExist() const {
1170 for (auto shader
: attached_shaders_
) {
1177 bool Program::CanLink() const {
1178 for (auto shader
: attached_shaders_
) {
1179 if (!shader
|| !shader
->valid()) {
1186 bool Program::DetectShaderVersionMismatch() const {
1187 int version
= Shader::kUndefinedShaderVersion
;
1188 for (auto shader
: attached_shaders_
) {
1190 if (version
!= Shader::kUndefinedShaderVersion
&&
1191 shader
->shader_version() != version
) {
1194 version
= shader
->shader_version();
1195 DCHECK(version
!= Shader::kUndefinedShaderVersion
);
1201 bool Program::DetectAttribLocationBindingConflicts() const {
1202 std::set
<GLint
> location_binding_used
;
1203 for (const auto& key_value
: bind_attrib_location_map_
) {
1204 // Find out if an attribute is statically used in this program's shaders.
1205 const sh::Attribute
* attrib
= NULL
;
1206 const std::string
* mapped_name
= GetAttribMappedName(key_value
.first
);
1209 for (auto shader
: attached_shaders_
) {
1210 if (!shader
|| !shader
->valid())
1212 attrib
= shader
->GetAttribInfo(*mapped_name
);
1214 if (attrib
->staticUse
)
1221 size_t num_of_locations
= 1;
1222 switch (attrib
->type
) {
1224 num_of_locations
= 2;
1227 num_of_locations
= 3;
1230 num_of_locations
= 4;
1235 for (size_t ii
= 0; ii
< num_of_locations
; ++ii
) {
1236 GLint loc
= key_value
.second
+ ii
;
1237 auto result
= location_binding_used
.insert(loc
);
1246 bool Program::DetectUniformLocationBindingConflicts() const {
1247 std::set
<GLint
> location_binding_used
;
1248 for (auto it
: bind_uniform_location_map_
) {
1249 // Find out if an attribute is statically used in this program's shaders.
1250 const sh::Uniform
* uniform
= nullptr;
1251 const std::string
* mapped_name
= GetUniformMappedName(it
.first
);
1254 for (auto shader
: attached_shaders_
) {
1255 if (!shader
|| !shader
->valid())
1257 uniform
= shader
->GetUniformInfo(*mapped_name
);
1259 if (uniform
->staticUse
)
1266 auto result
= location_binding_used
.insert(it
.second
);
1274 bool Program::DetectUniformsMismatch(std::string
* conflicting_name
) const {
1275 typedef std::map
<std::string
, const sh::Uniform
*> UniformPointerMap
;
1276 UniformPointerMap uniform_pointer_map
;
1277 for (auto shader
: attached_shaders_
) {
1278 const UniformMap
& shader_uniforms
= shader
->uniform_map();
1279 for (const auto& key_value
: shader_uniforms
) {
1280 const std::string
& name
= key_value
.first
;
1281 UniformPointerMap::iterator hit
= uniform_pointer_map
.find(name
);
1282 if (hit
== uniform_pointer_map
.end()) {
1283 uniform_pointer_map
[name
] = &(key_value
.second
);
1285 // If a uniform is in the map, i.e., it has already been declared by
1286 // another shader, then the type, precision, etc. must match.
1287 if (hit
->second
->isSameUniformAtLinkTime(key_value
.second
))
1289 *conflicting_name
= name
;
1297 bool Program::DetectVaryingsMismatch(std::string
* conflicting_name
) const {
1298 DCHECK(attached_shaders_
[0].get() &&
1299 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1300 attached_shaders_
[1].get() &&
1301 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1302 const VaryingMap
* vertex_varyings
= &(attached_shaders_
[0]->varying_map());
1303 const VaryingMap
* fragment_varyings
= &(attached_shaders_
[1]->varying_map());
1305 int shader_version
= attached_shaders_
[0]->shader_version();
1307 for (const auto& key_value
: *fragment_varyings
) {
1308 const std::string
& name
= key_value
.first
;
1309 if (IsBuiltInFragmentVarying(name
))
1312 VaryingMap::const_iterator hit
= vertex_varyings
->find(name
);
1313 if (hit
== vertex_varyings
->end()) {
1314 if (key_value
.second
.staticUse
) {
1315 *conflicting_name
= name
;
1321 if (!hit
->second
.isSameVaryingAtLinkTime(key_value
.second
,
1323 *conflicting_name
= name
;
1331 bool Program::DetectBuiltInInvariantConflicts() const {
1332 DCHECK(attached_shaders_
[0].get() &&
1333 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1334 attached_shaders_
[1].get() &&
1335 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1336 const VaryingMap
& vertex_varyings
= attached_shaders_
[0]->varying_map();
1337 const VaryingMap
& fragment_varyings
= attached_shaders_
[1]->varying_map();
1339 bool gl_position_invariant
= IsBuiltInInvariant(
1340 vertex_varyings
, "gl_Position");
1341 bool gl_point_size_invariant
= IsBuiltInInvariant(
1342 vertex_varyings
, "gl_PointSize");
1344 bool gl_frag_coord_invariant
= IsBuiltInInvariant(
1345 fragment_varyings
, "gl_FragCoord");
1346 bool gl_point_coord_invariant
= IsBuiltInInvariant(
1347 fragment_varyings
, "gl_PointCoord");
1349 return ((gl_frag_coord_invariant
&& !gl_position_invariant
) ||
1350 (gl_point_coord_invariant
&& !gl_point_size_invariant
));
1353 bool Program::DetectGlobalNameConflicts(std::string
* conflicting_name
) const {
1354 DCHECK(attached_shaders_
[0].get() &&
1355 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1356 attached_shaders_
[1].get() &&
1357 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1358 const UniformMap
* uniforms
[2];
1359 uniforms
[0] = &(attached_shaders_
[0]->uniform_map());
1360 uniforms
[1] = &(attached_shaders_
[1]->uniform_map());
1361 const AttributeMap
* attribs
=
1362 &(attached_shaders_
[0]->attrib_map());
1364 for (const auto& key_value
: *attribs
) {
1365 for (int ii
= 0; ii
< 2; ++ii
) {
1366 if (uniforms
[ii
]->find(key_value
.first
) != uniforms
[ii
]->end()) {
1367 *conflicting_name
= key_value
.first
;
1375 bool Program::CheckVaryingsPacking(
1376 Program::VaryingsPackingOption option
) const {
1377 DCHECK(attached_shaders_
[0].get() &&
1378 attached_shaders_
[0]->shader_type() == GL_VERTEX_SHADER
&&
1379 attached_shaders_
[1].get() &&
1380 attached_shaders_
[1]->shader_type() == GL_FRAGMENT_SHADER
);
1381 const VaryingMap
* vertex_varyings
= &(attached_shaders_
[0]->varying_map());
1382 const VaryingMap
* fragment_varyings
= &(attached_shaders_
[1]->varying_map());
1384 std::map
<std::string
, ShVariableInfo
> combined_map
;
1386 for (const auto& key_value
: *fragment_varyings
) {
1387 if (!key_value
.second
.staticUse
&& option
== kCountOnlyStaticallyUsed
)
1389 if (!IsBuiltInFragmentVarying(key_value
.first
)) {
1390 VaryingMap::const_iterator vertex_iter
=
1391 vertex_varyings
->find(key_value
.first
);
1392 if (vertex_iter
== vertex_varyings
->end() ||
1393 (!vertex_iter
->second
.staticUse
&&
1394 option
== kCountOnlyStaticallyUsed
))
1399 var
.type
= static_cast<sh::GLenum
>(key_value
.second
.type
);
1400 var
.size
= std::max(1u, key_value
.second
.arraySize
);
1401 combined_map
[key_value
.first
] = var
;
1404 if (combined_map
.size() == 0)
1406 scoped_ptr
<ShVariableInfo
[]> variables(
1407 new ShVariableInfo
[combined_map
.size()]);
1409 for (const auto& key_value
: combined_map
) {
1410 variables
[index
].type
= key_value
.second
.type
;
1411 variables
[index
].size
= key_value
.second
.size
;
1414 return ShCheckVariablesWithinPackingLimits(
1415 static_cast<int>(manager_
->max_varying_vectors()),
1417 combined_map
.size());
1420 void Program::GetProgramInfo(
1421 ProgramManager
* manager
, CommonDecoder::Bucket
* bucket
) const {
1422 // NOTE: It seems to me the math in here does not need check for overflow
1423 // because the data being calucated from has various small limits. The max
1424 // number of attribs + uniforms is somewhere well under 1024. The maximum size
1425 // of an identifier is 256 characters.
1426 uint32 num_locations
= 0;
1427 uint32 total_string_size
= 0;
1429 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
1430 const VertexAttrib
& info
= attrib_infos_
[ii
];
1432 total_string_size
+= info
.name
.size();
1435 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
1436 const UniformInfo
& info
= uniform_infos_
[ii
];
1437 if (info
.IsValid()) {
1438 num_locations
+= info
.element_locations
.size();
1439 total_string_size
+= info
.name
.size();
1443 uint32 num_inputs
= attrib_infos_
.size() + num_uniforms_
;
1444 uint32 input_size
= num_inputs
* sizeof(ProgramInput
);
1445 uint32 location_size
= num_locations
* sizeof(int32
);
1446 uint32 size
= sizeof(ProgramInfoHeader
) +
1447 input_size
+ location_size
+ total_string_size
;
1449 bucket
->SetSize(size
);
1450 ProgramInfoHeader
* header
= bucket
->GetDataAs
<ProgramInfoHeader
*>(0, size
);
1451 ProgramInput
* inputs
= bucket
->GetDataAs
<ProgramInput
*>(
1452 sizeof(ProgramInfoHeader
), input_size
);
1453 int32
* locations
= bucket
->GetDataAs
<int32
*>(
1454 sizeof(ProgramInfoHeader
) + input_size
, location_size
);
1455 char* strings
= bucket
->GetDataAs
<char*>(
1456 sizeof(ProgramInfoHeader
) + input_size
+ location_size
,
1463 header
->link_status
= link_status_
;
1464 header
->num_attribs
= attrib_infos_
.size();
1465 header
->num_uniforms
= num_uniforms_
;
1467 for (size_t ii
= 0; ii
< attrib_infos_
.size(); ++ii
) {
1468 const VertexAttrib
& info
= attrib_infos_
[ii
];
1469 inputs
->size
= info
.size
;
1470 inputs
->type
= info
.type
;
1471 inputs
->location_offset
= ComputeOffset(header
, locations
);
1472 inputs
->name_offset
= ComputeOffset(header
, strings
);
1473 inputs
->name_length
= info
.name
.size();
1474 *locations
++ = info
.location
;
1475 memcpy(strings
, info
.name
.c_str(), info
.name
.size());
1476 strings
+= info
.name
.size();
1480 for (size_t ii
= 0; ii
< uniform_infos_
.size(); ++ii
) {
1481 const UniformInfo
& info
= uniform_infos_
[ii
];
1482 if (info
.IsValid()) {
1483 inputs
->size
= info
.size
;
1484 inputs
->type
= info
.type
;
1485 inputs
->location_offset
= ComputeOffset(header
, locations
);
1486 inputs
->name_offset
= ComputeOffset(header
, strings
);
1487 inputs
->name_length
= info
.name
.size();
1488 DCHECK(static_cast<size_t>(info
.size
) == info
.element_locations
.size());
1489 for (size_t jj
= 0; jj
< info
.element_locations
.size(); ++jj
) {
1490 if (info
.element_locations
[jj
] == -1)
1493 *locations
++ = ProgramManager::MakeFakeLocation(ii
, jj
);
1495 memcpy(strings
, info
.name
.c_str(), info
.name
.size());
1496 strings
+= info
.name
.size();
1501 DCHECK_EQ(ComputeOffset(header
, strings
), size
);
1504 bool Program::GetUniformBlocks(CommonDecoder::Bucket
* bucket
) const {
1505 // The data is packed into the bucket in the following order
1507 // 2) N entries of block data (except for name and indices)
1508 // 3) name1, indices1, name2, indices2, ..., nameN, indicesN
1510 // We query all the data directly through GL calls, assuming they are
1511 // cheap through MANGLE.
1514 GLuint program
= service_id();
1516 uint32_t header_size
= sizeof(UniformBlocksHeader
);
1517 bucket
->SetSize(header_size
); // In case we fail.
1519 uint32_t num_uniform_blocks
= 0;
1520 GLint param
= GL_FALSE
;
1521 // We assume program is a valid program service id.
1522 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1523 if (param
== GL_TRUE
) {
1525 glGetProgramiv(program
, GL_ACTIVE_UNIFORM_BLOCKS
, ¶m
);
1526 num_uniform_blocks
= static_cast<uint32_t>(param
);
1528 if (num_uniform_blocks
== 0) {
1529 // Although spec allows an implementation to return uniform block info
1530 // even if a link fails, for consistency, we disallow that.
1534 std::vector
<UniformBlockInfo
> blocks(num_uniform_blocks
);
1535 base::CheckedNumeric
<uint32_t> size
= sizeof(UniformBlockInfo
);
1536 size
*= num_uniform_blocks
;
1537 uint32_t entry_size
= size
.ValueOrDefault(0);
1538 size
+= header_size
;
1539 std::vector
<std::string
> names(num_uniform_blocks
);
1540 GLint max_name_length
= 0;
1542 program
, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH
, &max_name_length
);
1543 std::vector
<GLchar
> buffer(max_name_length
);
1545 for (uint32_t ii
= 0; ii
< num_uniform_blocks
; ++ii
) {
1547 glGetActiveUniformBlockiv(program
, ii
, GL_UNIFORM_BLOCK_BINDING
, ¶m
);
1548 blocks
[ii
].binding
= static_cast<uint32_t>(param
);
1551 glGetActiveUniformBlockiv(program
, ii
, GL_UNIFORM_BLOCK_DATA_SIZE
, ¶m
);
1552 blocks
[ii
].data_size
= static_cast<uint32_t>(param
);
1554 blocks
[ii
].name_offset
= size
.ValueOrDefault(0);
1556 glGetActiveUniformBlockiv(
1557 program
, ii
, GL_UNIFORM_BLOCK_NAME_LENGTH
, ¶m
);
1558 DCHECK_GE(max_name_length
, param
);
1559 memset(&buffer
[0], 0, param
);
1561 glGetActiveUniformBlockName(
1562 program
, ii
, static_cast<GLsizei
>(param
), &length
, &buffer
[0]);
1563 DCHECK_EQ(param
, length
+ 1);
1564 names
[ii
] = std::string(&buffer
[0], length
);
1565 // TODO(zmo): optimize the name mapping lookup.
1566 const std::string
* original_name
= GetOriginalNameFromHashedName(names
[ii
]);
1568 names
[ii
] = *original_name
;
1569 blocks
[ii
].name_length
= names
[ii
].size() + 1;
1570 size
+= blocks
[ii
].name_length
;
1573 glGetActiveUniformBlockiv(
1574 program
, ii
, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS
, ¶m
);
1575 blocks
[ii
].active_uniforms
= static_cast<uint32_t>(param
);
1576 blocks
[ii
].active_uniform_offset
= size
.ValueOrDefault(0);
1577 base::CheckedNumeric
<uint32_t> indices_size
= blocks
[ii
].active_uniforms
;
1578 indices_size
*= sizeof(uint32_t);
1579 if (!indices_size
.IsValid())
1581 size
+= indices_size
.ValueOrDefault(0);
1584 glGetActiveUniformBlockiv(
1585 program
, ii
, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER
, ¶m
);
1586 blocks
[ii
].referenced_by_vertex_shader
= static_cast<uint32_t>(param
);
1589 glGetActiveUniformBlockiv(
1590 program
, ii
, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
, ¶m
);
1591 blocks
[ii
].referenced_by_fragment_shader
= static_cast<uint32_t>(param
);
1593 if (!size
.IsValid())
1595 uint32_t total_size
= size
.ValueOrDefault(0);
1596 DCHECK_LE(header_size
+ entry_size
, total_size
);
1597 uint32_t data_size
= total_size
- header_size
- entry_size
;
1599 bucket
->SetSize(total_size
);
1600 UniformBlocksHeader
* header
=
1601 bucket
->GetDataAs
<UniformBlocksHeader
*>(0, header_size
);
1602 UniformBlockInfo
* entries
= bucket
->GetDataAs
<UniformBlockInfo
*>(
1603 header_size
, entry_size
);
1604 char* data
= bucket
->GetDataAs
<char*>(header_size
+ entry_size
, data_size
);
1609 // Copy over data for the header and entries.
1610 header
->num_uniform_blocks
= num_uniform_blocks
;
1611 memcpy(entries
, &blocks
[0], entry_size
);
1613 std::vector
<GLint
> params
;
1614 for (uint32_t ii
= 0; ii
< num_uniform_blocks
; ++ii
) {
1615 // Get active uniform name.
1616 memcpy(data
, names
[ii
].c_str(), names
[ii
].length() + 1);
1617 data
+= names
[ii
].length() + 1;
1619 // Get active uniform indices.
1620 if (params
.size() < blocks
[ii
].active_uniforms
)
1621 params
.resize(blocks
[ii
].active_uniforms
);
1622 uint32_t num_bytes
= blocks
[ii
].active_uniforms
* sizeof(GLint
);
1623 memset(¶ms
[0], 0, num_bytes
);
1624 glGetActiveUniformBlockiv(
1625 program
, ii
, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
, ¶ms
[0]);
1626 uint32_t* indices
= reinterpret_cast<uint32_t*>(data
);
1627 for (uint32_t uu
= 0; uu
< blocks
[ii
].active_uniforms
; ++uu
) {
1628 indices
[uu
] = static_cast<uint32_t>(params
[uu
]);
1632 DCHECK_EQ(ComputeOffset(header
, data
), total_size
);
1636 bool Program::GetTransformFeedbackVaryings(
1637 CommonDecoder::Bucket
* bucket
) const {
1638 // The data is packed into the bucket in the following order
1640 // 2) N entries of varying data (except for name)
1641 // 3) name1, name2, ..., nameN
1643 // We query all the data directly through GL calls, assuming they are
1644 // cheap through MANGLE.
1647 GLuint program
= service_id();
1649 uint32_t header_size
= sizeof(TransformFeedbackVaryingsHeader
);
1650 bucket
->SetSize(header_size
); // In case we fail.
1652 GLenum transform_feedback_buffer_mode
= 0;
1654 glGetProgramiv(program
, GL_TRANSFORM_FEEDBACK_BUFFER_MODE
, ¶m
);
1655 transform_feedback_buffer_mode
= static_cast<GLenum
>(param
);
1657 uint32_t num_transform_feedback_varyings
= 0;
1659 // We assume program is a valid program service id.
1660 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1661 if (param
== GL_TRUE
) {
1663 glGetProgramiv(program
, GL_TRANSFORM_FEEDBACK_VARYINGS
, ¶m
);
1664 num_transform_feedback_varyings
= static_cast<uint32_t>(param
);
1666 if (num_transform_feedback_varyings
== 0) {
1667 TransformFeedbackVaryingsHeader
* header
=
1668 bucket
->GetDataAs
<TransformFeedbackVaryingsHeader
*>(0, header_size
);
1669 header
->transform_feedback_buffer_mode
= transform_feedback_buffer_mode
;
1673 std::vector
<TransformFeedbackVaryingInfo
> varyings(
1674 num_transform_feedback_varyings
);
1675 base::CheckedNumeric
<uint32_t> size
= sizeof(TransformFeedbackVaryingInfo
);
1676 size
*= num_transform_feedback_varyings
;
1677 uint32_t entry_size
= size
.ValueOrDefault(0);
1678 size
+= header_size
;
1679 std::vector
<std::string
> names(num_transform_feedback_varyings
);
1680 GLint max_name_length
= 0;
1682 program
, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH
, &max_name_length
);
1683 if (max_name_length
< 1)
1684 max_name_length
= 1;
1685 std::vector
<char> buffer(max_name_length
);
1686 for (uint32_t ii
= 0; ii
< num_transform_feedback_varyings
; ++ii
) {
1687 GLsizei var_size
= 0;
1688 GLsizei var_name_length
= 0;
1689 GLenum var_type
= 0;
1690 glGetTransformFeedbackVarying(
1691 program
, ii
, max_name_length
,
1692 &var_name_length
, &var_size
, &var_type
, &buffer
[0]);
1693 varyings
[ii
].size
= static_cast<uint32_t>(var_size
);
1694 varyings
[ii
].type
= static_cast<uint32_t>(var_type
);
1695 varyings
[ii
].name_offset
= static_cast<uint32_t>(size
.ValueOrDefault(0));
1696 DCHECK_GT(max_name_length
, var_name_length
);
1697 names
[ii
] = std::string(&buffer
[0], var_name_length
);
1698 // TODO(zmo): optimize the name mapping lookup.
1699 const std::string
* original_name
= GetOriginalNameFromHashedName(names
[ii
]);
1701 names
[ii
] = *original_name
;
1702 varyings
[ii
].name_length
= names
[ii
].size() + 1;
1703 size
+= names
[ii
].size();
1706 if (!size
.IsValid())
1708 uint32_t total_size
= size
.ValueOrDefault(0);
1709 DCHECK_LE(header_size
+ entry_size
, total_size
);
1710 uint32_t data_size
= total_size
- header_size
- entry_size
;
1712 bucket
->SetSize(total_size
);
1713 TransformFeedbackVaryingsHeader
* header
=
1714 bucket
->GetDataAs
<TransformFeedbackVaryingsHeader
*>(0, header_size
);
1715 TransformFeedbackVaryingInfo
* entries
=
1716 bucket
->GetDataAs
<TransformFeedbackVaryingInfo
*>(header_size
, entry_size
);
1717 char* data
= bucket
->GetDataAs
<char*>(header_size
+ entry_size
, data_size
);
1722 // Copy over data for the header and entries.
1723 header
->transform_feedback_buffer_mode
= transform_feedback_buffer_mode
;
1724 header
->num_transform_feedback_varyings
= num_transform_feedback_varyings
;
1725 memcpy(entries
, &varyings
[0], entry_size
);
1727 for (uint32_t ii
= 0; ii
< num_transform_feedback_varyings
; ++ii
) {
1728 memcpy(data
, names
[ii
].c_str(), names
[ii
].length() + 1);
1729 data
+= names
[ii
].length() + 1;
1731 DCHECK_EQ(ComputeOffset(header
, data
), total_size
);
1735 bool Program::GetUniformsES3(CommonDecoder::Bucket
* bucket
) const {
1736 // The data is packed into the bucket in the following order
1738 // 2) N entries of UniformES3Info
1740 // We query all the data directly through GL calls, assuming they are
1741 // cheap through MANGLE.
1744 GLuint program
= service_id();
1746 uint32_t header_size
= sizeof(UniformsES3Header
);
1747 bucket
->SetSize(header_size
); // In case we fail.
1750 GLint param
= GL_FALSE
;
1751 // We assume program is a valid program service id.
1752 glGetProgramiv(program
, GL_LINK_STATUS
, ¶m
);
1753 if (param
== GL_TRUE
) {
1755 glGetProgramiv(program
, GL_ACTIVE_UNIFORMS
, &count
);
1761 base::CheckedNumeric
<uint32_t> size
= sizeof(UniformES3Info
);
1763 uint32_t entry_size
= size
.ValueOrDefault(0);
1764 size
+= header_size
;
1765 if (!size
.IsValid())
1767 uint32_t total_size
= size
.ValueOrDefault(0);
1768 bucket
->SetSize(total_size
);
1769 UniformsES3Header
* header
=
1770 bucket
->GetDataAs
<UniformsES3Header
*>(0, header_size
);
1772 header
->num_uniforms
= static_cast<uint32_t>(count
);
1774 // Instead of GetDataAs<UniformES3Info*>, we do GetDataAs<int32_t>. This is
1775 // because struct UniformES3Info is defined as five int32_t.
1776 // By doing this, we can fill the structs through loops.
1778 bucket
->GetDataAs
<int32_t*>(header_size
, entry_size
);
1780 const size_t kStride
= sizeof(UniformES3Info
) / sizeof(int32_t);
1782 const GLenum kPname
[] = {
1783 GL_UNIFORM_BLOCK_INDEX
,
1785 GL_UNIFORM_ARRAY_STRIDE
,
1786 GL_UNIFORM_MATRIX_STRIDE
,
1787 GL_UNIFORM_IS_ROW_MAJOR
,
1789 const GLint kDefaultValue
[] = { -1, -1, -1, -1, 0 };
1790 const size_t kNumPnames
= arraysize(kPname
);
1791 std::vector
<GLuint
> indices(count
);
1792 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1795 std::vector
<GLint
> params(count
);
1796 for (size_t pname_index
= 0; pname_index
< kNumPnames
; ++pname_index
) {
1797 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1798 params
[ii
] = kDefaultValue
[pname_index
];
1800 glGetActiveUniformsiv(
1801 program
, count
, &indices
[0], kPname
[pname_index
], ¶ms
[0]);
1802 for (GLsizei ii
= 0; ii
< count
; ++ii
) {
1803 entries
[kStride
* ii
+ pname_index
] = params
[ii
];
1809 void Program::TransformFeedbackVaryings(GLsizei count
,
1810 const char* const* varyings
,
1811 GLenum buffer_mode
) {
1812 transform_feedback_varyings_
.clear();
1813 for (GLsizei i
= 0; i
< count
; ++i
) {
1814 transform_feedback_varyings_
.push_back(std::string(varyings
[i
]));
1816 transform_feedback_buffer_mode_
= buffer_mode
;
1819 Program::~Program() {
1821 if (manager_
->have_context_
) {
1822 glDeleteProgram(service_id());
1824 manager_
->StopTracking(this);
1830 ProgramManager::ProgramManager(ProgramCache
* program_cache
,
1831 uint32 max_varying_vectors
)
1832 : program_count_(0),
1833 have_context_(true),
1834 program_cache_(program_cache
),
1835 max_varying_vectors_(max_varying_vectors
) { }
1837 ProgramManager::~ProgramManager() {
1838 DCHECK(programs_
.empty());
1841 void ProgramManager::Destroy(bool have_context
) {
1842 have_context_
= have_context
;
1846 void ProgramManager::StartTracking(Program
* /* program */) {
1850 void ProgramManager::StopTracking(Program
* /* program */) {
1854 Program
* ProgramManager::CreateProgram(
1855 GLuint client_id
, GLuint service_id
) {
1856 std::pair
<ProgramMap::iterator
, bool> result
=
1858 std::make_pair(client_id
,
1859 scoped_refptr
<Program
>(
1860 new Program(this, service_id
))));
1861 DCHECK(result
.second
);
1862 return result
.first
->second
.get();
1865 Program
* ProgramManager::GetProgram(GLuint client_id
) {
1866 ProgramMap::iterator it
= programs_
.find(client_id
);
1867 return it
!= programs_
.end() ? it
->second
.get() : NULL
;
1870 bool ProgramManager::GetClientId(GLuint service_id
, GLuint
* client_id
) const {
1871 // This doesn't need to be fast. It's only used during slow queries.
1872 for (const auto& key_value
: programs_
) {
1873 if (key_value
.second
->service_id() == service_id
) {
1874 *client_id
= key_value
.first
;
1881 ProgramCache
* ProgramManager::program_cache() const {
1882 return program_cache_
;
1885 bool ProgramManager::IsOwned(Program
* program
) const {
1886 for (const auto& key_value
: programs_
) {
1887 if (key_value
.second
.get() == program
) {
1894 void ProgramManager::RemoveProgramInfoIfUnused(
1895 ShaderManager
* shader_manager
, Program
* program
) {
1896 DCHECK(shader_manager
);
1898 DCHECK(IsOwned(program
));
1899 if (program
->IsDeleted() && !program
->InUse()) {
1900 program
->DetachShaders(shader_manager
);
1901 for (ProgramMap::iterator it
= programs_
.begin();
1902 it
!= programs_
.end(); ++it
) {
1903 if (it
->second
.get() == program
) {
1904 programs_
.erase(it
);
1912 void ProgramManager::MarkAsDeleted(
1913 ShaderManager
* shader_manager
,
1915 DCHECK(shader_manager
);
1917 DCHECK(IsOwned(program
));
1918 program
->MarkAsDeleted();
1919 RemoveProgramInfoIfUnused(shader_manager
, program
);
1922 void ProgramManager::UseProgram(Program
* program
) {
1924 DCHECK(IsOwned(program
));
1925 program
->IncUseCount();
1928 void ProgramManager::UnuseProgram(
1929 ShaderManager
* shader_manager
,
1931 DCHECK(shader_manager
);
1933 DCHECK(IsOwned(program
));
1934 program
->DecUseCount();
1935 RemoveProgramInfoIfUnused(shader_manager
, program
);
1938 void ProgramManager::ClearUniforms(Program
* program
) {
1940 program
->ClearUniforms(&zero_
);
1943 int32
ProgramManager::MakeFakeLocation(int32 index
, int32 element
) {
1944 return index
+ element
* 0x10000;
1947 } // namespace gles2