Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / gpu / command_buffer / client / program_info_manager.cc
blob0ab53e32b6b8033408b913e0ac767f92551e3e3b
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/client/program_info_manager.h"
7 namespace {
9 template<typename T> static T LocalGetAs(
10 const std::vector<int8>& data, uint32 offset, size_t size) {
11 const int8* p = &data[0] + offset;
12 if (offset + size > data.size()) {
13 NOTREACHED();
14 return NULL;
16 return static_cast<T>(static_cast<const void*>(p));
19 } // namespace anonymous
21 namespace gpu {
22 namespace gles2 {
24 ProgramInfoManager::Program::VertexAttrib::VertexAttrib(
25 GLsizei _size, GLenum _type, const std::string& _name, GLint _location)
26 : size(_size),
27 type(_type),
28 location(_location),
29 name(_name) {
32 ProgramInfoManager::Program::VertexAttrib::~VertexAttrib() {
35 ProgramInfoManager::Program::UniformInfo::UniformInfo(
36 GLsizei _size, GLenum _type, const std::string& _name)
37 : size(_size),
38 type(_type),
39 name(_name) {
40 is_array = (!name.empty() && name[name.size() - 1] == ']');
41 DCHECK(!(size > 1 && !is_array));
44 ProgramInfoManager::Program::UniformInfo::~UniformInfo() {
47 ProgramInfoManager::Program::UniformES3::UniformES3()
48 : block_index(-1),
49 offset(-1),
50 array_stride(-1),
51 matrix_stride(-1),
52 is_row_major(0) {
55 ProgramInfoManager::Program::UniformES3::~UniformES3() {
58 ProgramInfoManager::Program::UniformBlock::UniformBlock()
59 : binding(0),
60 data_size(0),
61 referenced_by_vertex_shader(false),
62 referenced_by_fragment_shader(false) {
65 ProgramInfoManager::Program::UniformBlock::~UniformBlock() {
68 ProgramInfoManager::Program::TransformFeedbackVarying::
69 TransformFeedbackVarying()
70 : size(0),
71 type(0) {
74 ProgramInfoManager::Program::TransformFeedbackVarying::
75 ~TransformFeedbackVarying() {
78 ProgramInfoManager::Program::Program()
79 : cached_es2_(false),
80 max_attrib_name_length_(0),
81 max_uniform_name_length_(0),
82 link_status_(false),
83 cached_es3_uniform_blocks_(false),
84 active_uniform_block_max_name_length_(0),
85 cached_es3_transform_feedback_varyings_(false),
86 transform_feedback_varying_max_length_(0),
87 cached_es3_uniformsiv_(false) {
90 ProgramInfoManager::Program::~Program() {
93 // TODO(gman): Add a faster lookup.
94 GLint ProgramInfoManager::Program::GetAttribLocation(
95 const std::string& name) const {
96 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
97 const VertexAttrib& info = attrib_infos_[ii];
98 if (info.name == name) {
99 return info.location;
102 return -1;
105 const ProgramInfoManager::Program::VertexAttrib*
106 ProgramInfoManager::Program::GetAttribInfo(GLint index) const {
107 return (static_cast<size_t>(index) < attrib_infos_.size()) ?
108 &attrib_infos_[index] : NULL;
111 const ProgramInfoManager::Program::UniformInfo*
112 ProgramInfoManager::Program::GetUniformInfo(GLint index) const {
113 return (static_cast<size_t>(index) < uniform_infos_.size()) ?
114 &uniform_infos_[index] : NULL;
117 const ProgramInfoManager::Program::UniformBlock*
118 ProgramInfoManager::Program::GetUniformBlock(GLuint index) const {
119 return (index < uniform_blocks_.size()) ? &uniform_blocks_[index] : NULL;
122 GLint ProgramInfoManager::Program::GetUniformLocation(
123 const std::string& name) const {
124 bool getting_array_location = false;
125 size_t open_pos = std::string::npos;
126 int index = 0;
127 if (!GLES2Util::ParseUniformName(
128 name, &open_pos, &index, &getting_array_location)) {
129 return -1;
131 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
132 const UniformInfo& info = uniform_infos_[ii];
133 if (info.name == name ||
134 (info.is_array &&
135 info.name.compare(0, info.name.size() - 3, name) == 0)) {
136 return info.element_locations[0];
137 } else if (getting_array_location && info.is_array) {
138 // Look for an array specification.
139 size_t open_pos_2 = info.name.find_last_of('[');
140 if (open_pos_2 == open_pos &&
141 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
142 if (index >= 0 && index < info.size) {
143 return info.element_locations[index];
148 return -1;
151 GLuint ProgramInfoManager::Program::GetUniformIndex(
152 const std::string& name) const {
153 // TODO(zmo): Maybe build a hashed_map for faster lookup.
154 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
155 const UniformInfo& info = uniform_infos_[ii];
156 // For an array, either "var" or "var[0]" is considered as a match.
157 // See "OpenGL ES 3.0.0, Section 2.11.3 Program Objects."
158 if (info.name == name ||
159 (info.is_array &&
160 info.name.compare(0, info.name.size() - 3, name) == 0)) {
161 return ii;
164 return GL_INVALID_INDEX;
167 GLint ProgramInfoManager::Program::GetFragDataLocation(
168 const std::string& name) const {
169 base::hash_map<std::string, GLint>::const_iterator iter =
170 frag_data_locations_.find(name);
171 if (iter == frag_data_locations_.end())
172 return -1;
173 return iter->second;
176 void ProgramInfoManager::Program::CacheFragDataLocation(
177 const std::string& name, GLint loc) {
178 frag_data_locations_[name] = loc;
181 bool ProgramInfoManager::Program::GetProgramiv(
182 GLenum pname, GLint* params) {
183 switch (pname) {
184 case GL_LINK_STATUS:
185 *params = static_cast<GLint>(link_status_);
186 return true;
187 case GL_ACTIVE_ATTRIBUTES:
188 *params = static_cast<GLint>(attrib_infos_.size());
189 return true;
190 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
191 *params = static_cast<GLint>(max_attrib_name_length_);
192 return true;
193 case GL_ACTIVE_UNIFORMS:
194 *params = static_cast<GLint>(uniform_infos_.size());
195 return true;
196 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
197 *params = static_cast<GLint>(max_uniform_name_length_);
198 return true;
199 case GL_ACTIVE_UNIFORM_BLOCKS:
200 *params = static_cast<GLint>(uniform_blocks_.size());
201 return true;
202 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
203 *params = static_cast<GLint>(active_uniform_block_max_name_length_);
204 return true;
205 case GL_TRANSFORM_FEEDBACK_VARYINGS:
206 *params = static_cast<GLint>(transform_feedback_varyings_.size());
207 return true;
208 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
209 *params = static_cast<GLint>(transform_feedback_varying_max_length_);
210 return true;
211 default:
212 NOTREACHED();
213 break;
215 return false;
218 GLuint ProgramInfoManager::Program::GetUniformBlockIndex(
219 const std::string& name) const {
220 for (size_t ii = 0; ii < uniform_blocks_.size(); ++ii) {
221 if (uniform_blocks_[ii].name == name) {
222 return static_cast<GLuint>(ii);
225 return GL_INVALID_INDEX;
228 void ProgramInfoManager::Program::UniformBlockBinding(
229 GLuint index , GLuint binding) {
230 if (index < uniform_blocks_.size()) {
231 uniform_blocks_[index].binding = binding;
235 const ProgramInfoManager::Program::TransformFeedbackVarying*
236 ProgramInfoManager::Program::GetTransformFeedbackVarying(GLuint index) const {
237 return (index < transform_feedback_varyings_.size()) ?
238 &transform_feedback_varyings_[index] : NULL;
241 bool ProgramInfoManager::Program::GetUniformsiv(
242 GLsizei count, const GLuint* indices, GLenum pname, GLint* params) {
243 if (count == 0) {
244 // At this point, pname has already been validated.
245 return true;
247 DCHECK(count > 0 && indices);
248 size_t num_uniforms = uniform_infos_.size();
249 if (num_uniforms == 0) {
250 num_uniforms = uniforms_es3_.size();
252 if (static_cast<size_t>(count) > num_uniforms) {
253 return false;
255 for (GLsizei ii = 0; ii < count; ++ii) {
256 if (indices[ii] >= num_uniforms) {
257 return false;
260 if (!params) {
261 return true;
263 switch (pname) {
264 case GL_UNIFORM_SIZE:
265 DCHECK_EQ(num_uniforms, uniform_infos_.size());
266 for (GLsizei ii = 0; ii < count; ++ii) {
267 params[ii] = static_cast<GLint>(uniform_infos_[indices[ii]].size);
269 return true;
270 case GL_UNIFORM_TYPE:
271 DCHECK_EQ(num_uniforms, uniform_infos_.size());
272 for (GLsizei ii = 0; ii < count; ++ii) {
273 params[ii] = static_cast<GLint>(uniform_infos_[indices[ii]].type);
275 return true;
276 case GL_UNIFORM_NAME_LENGTH:
277 DCHECK_EQ(num_uniforms, uniform_infos_.size());
278 for (GLsizei ii = 0; ii < count; ++ii) {
279 params[ii] = static_cast<GLint>(
280 uniform_infos_[indices[ii]].name.length() + 1);
282 return true;
283 case GL_UNIFORM_BLOCK_INDEX:
284 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
285 for (GLsizei ii = 0; ii < count; ++ii) {
286 params[ii] = uniforms_es3_[indices[ii]].block_index;
288 return true;
289 case GL_UNIFORM_OFFSET:
290 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
291 for (GLsizei ii = 0; ii < count; ++ii) {
292 params[ii] = uniforms_es3_[indices[ii]].offset;
294 return true;
295 case GL_UNIFORM_ARRAY_STRIDE:
296 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
297 for (GLsizei ii = 0; ii < count; ++ii) {
298 params[ii] = uniforms_es3_[indices[ii]].array_stride;
300 return true;
301 case GL_UNIFORM_MATRIX_STRIDE:
302 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
303 for (GLsizei ii = 0; ii < count; ++ii) {
304 params[ii] = uniforms_es3_[indices[ii]].matrix_stride;
306 return true;
307 case GL_UNIFORM_IS_ROW_MAJOR:
308 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
309 for (GLsizei ii = 0; ii < count; ++ii) {
310 params[ii] = uniforms_es3_[indices[ii]].is_row_major;
312 return true;
313 default:
314 NOTREACHED();
315 break;
317 return false;
320 void ProgramInfoManager::Program::UpdateES2(const std::vector<int8>& result) {
321 if (cached_es2_) {
322 return;
324 if (result.empty()) {
325 // This should only happen on a lost context.
326 return;
328 DCHECK_GE(result.size(), sizeof(ProgramInfoHeader));
329 const ProgramInfoHeader* header = LocalGetAs<const ProgramInfoHeader*>(
330 result, 0, sizeof(header));
331 link_status_ = header->link_status != 0;
332 if (!link_status_) {
333 return;
335 DCHECK_EQ(0u, attrib_infos_.size());
336 DCHECK_EQ(0u, uniform_infos_.size());
337 DCHECK_EQ(0, max_attrib_name_length_);
338 DCHECK_EQ(0, max_uniform_name_length_);
339 const ProgramInput* inputs = LocalGetAs<const ProgramInput*>(
340 result, sizeof(*header),
341 sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms));
342 const ProgramInput* input = inputs;
343 for (uint32 ii = 0; ii < header->num_attribs; ++ii) {
344 const int32* location = LocalGetAs<const int32*>(
345 result, input->location_offset, sizeof(int32));
346 const char* name_buf = LocalGetAs<const char*>(
347 result, input->name_offset, input->name_length);
348 std::string name(name_buf, input->name_length);
349 attrib_infos_.push_back(
350 VertexAttrib(input->size, input->type, name, *location));
351 max_attrib_name_length_ = std::max(
352 static_cast<GLsizei>(name.size() + 1), max_attrib_name_length_);
353 ++input;
355 for (uint32 ii = 0; ii < header->num_uniforms; ++ii) {
356 const int32* locations = LocalGetAs<const int32*>(
357 result, input->location_offset, sizeof(int32) * input->size);
358 const char* name_buf = LocalGetAs<const char*>(
359 result, input->name_offset, input->name_length);
360 std::string name(name_buf, input->name_length);
361 UniformInfo info(input->size, input->type, name);
362 max_uniform_name_length_ = std::max(
363 static_cast<GLsizei>(name.size() + 1), max_uniform_name_length_);
364 for (int32 jj = 0; jj < input->size; ++jj) {
365 info.element_locations.push_back(locations[jj]);
367 uniform_infos_.push_back(info);
368 ++input;
370 DCHECK_EQ(header->num_attribs + header->num_uniforms,
371 static_cast<uint32>(input - inputs));
372 cached_es2_ = true;
375 void ProgramInfoManager::Program::UpdateES3UniformBlocks(
376 const std::vector<int8>& result) {
377 if (cached_es3_uniform_blocks_) {
378 return;
380 if (result.empty()) {
381 // This should only happen on a lost context.
382 return;
384 DCHECK_EQ(0u, uniform_blocks_.size());
385 DCHECK_EQ(0u, active_uniform_block_max_name_length_);
387 // |result| comes from GPU process. We consider it trusted data. Therefore,
388 // no need to check for overflows as the GPU side did the checks already.
389 uint32_t header_size = sizeof(UniformBlocksHeader);
390 DCHECK_GE(result.size(), header_size);
391 const UniformBlocksHeader* header = LocalGetAs<const UniformBlocksHeader*>(
392 result, 0, header_size);
393 DCHECK(header);
394 if (header->num_uniform_blocks == 0) {
395 DCHECK_EQ(result.size(), header_size);
396 // TODO(zmo): Here we can't tell if no uniform blocks are defined, or
397 // the previous link failed.
398 return;
400 uniform_blocks_.resize(header->num_uniform_blocks);
402 uint32_t entry_size = sizeof(UniformBlockInfo) * header->num_uniform_blocks;
403 DCHECK_GE(result.size(), header_size + entry_size);
404 uint32_t data_size = result.size() - header_size - entry_size;
405 DCHECK_LT(0u, data_size);
406 const UniformBlockInfo* entries = LocalGetAs<const UniformBlockInfo*>(
407 result, header_size, entry_size);
408 DCHECK(entries);
409 const char* data = LocalGetAs<const char*>(
410 result, header_size + entry_size, data_size);
411 DCHECK(data);
413 uint32_t size = 0;
414 for (uint32_t ii = 0; ii < header->num_uniform_blocks; ++ii) {
415 uniform_blocks_[ii].binding = static_cast<GLuint>(entries[ii].binding);
416 uniform_blocks_[ii].data_size = static_cast<GLuint>(entries[ii].data_size);
417 uniform_blocks_[ii].active_uniform_indices.resize(
418 entries[ii].active_uniforms);
419 uniform_blocks_[ii].referenced_by_vertex_shader = static_cast<GLboolean>(
420 entries[ii].referenced_by_vertex_shader);
421 uniform_blocks_[ii].referenced_by_fragment_shader = static_cast<GLboolean>(
422 entries[ii].referenced_by_fragment_shader);
423 // Uniform block names can't be empty strings.
424 DCHECK_LT(1u, entries[ii].name_length);
425 if (entries[ii].name_length > active_uniform_block_max_name_length_) {
426 active_uniform_block_max_name_length_ = entries[ii].name_length;
428 size += entries[ii].name_length;
429 DCHECK_GE(data_size, size);
430 uniform_blocks_[ii].name = std::string(data, entries[ii].name_length - 1);
431 data += entries[ii].name_length;
432 size += entries[ii].active_uniforms * sizeof(uint32_t);
433 DCHECK_GE(data_size, size);
434 const uint32_t* indices = reinterpret_cast<const uint32_t*>(data);
435 for (uint32_t uu = 0; uu < entries[ii].active_uniforms; ++uu) {
436 uniform_blocks_[ii].active_uniform_indices[uu] =
437 static_cast<GLuint>(indices[uu]);
439 indices += entries[ii].active_uniforms;
440 data = reinterpret_cast<const char*>(indices);
442 DCHECK_EQ(data_size, size);
443 cached_es3_uniform_blocks_ = true;
446 void ProgramInfoManager::Program::UpdateES3Uniformsiv(
447 const std::vector<int8>& result) {
448 if (cached_es3_uniformsiv_) {
449 return;
451 if (result.empty()) {
452 // This should only happen on a lost context.
453 return;
455 DCHECK_EQ(0u, uniforms_es3_.size());
457 // |result| comes from GPU process. We consider it trusted data. Therefore,
458 // no need to check for overflows as the GPU side did the checks already.
459 uint32_t header_size = sizeof(UniformsES3Header);
460 DCHECK_GE(result.size(), header_size);
461 const UniformsES3Header* header = LocalGetAs<const UniformsES3Header*>(
462 result, 0, header_size);
463 DCHECK(header);
464 if (header->num_uniforms == 0) {
465 DCHECK_EQ(result.size(), header_size);
466 // TODO(zmo): Here we can't tell if no uniforms are defined, or
467 // the previous link failed.
468 return;
470 uniforms_es3_.resize(header->num_uniforms);
472 uint32_t entry_size = sizeof(UniformES3Info) * header->num_uniforms;
473 DCHECK_EQ(result.size(), header_size + entry_size);
474 const UniformES3Info* entries = LocalGetAs<const UniformES3Info*>(
475 result, header_size, entry_size);
476 DCHECK(entries);
478 for (uint32_t ii = 0; ii < header->num_uniforms; ++ii) {
479 uniforms_es3_[ii].block_index = entries[ii].block_index;
480 uniforms_es3_[ii].offset = entries[ii].offset;
481 uniforms_es3_[ii].array_stride = entries[ii].array_stride;
482 uniforms_es3_[ii].matrix_stride = entries[ii].matrix_stride;
483 uniforms_es3_[ii].is_row_major = entries[ii].is_row_major;
485 cached_es3_uniformsiv_ = true;
488 void ProgramInfoManager::Program::UpdateES3TransformFeedbackVaryings(
489 const std::vector<int8>& result) {
490 if (cached_es3_transform_feedback_varyings_) {
491 return;
493 if (result.empty()) {
494 // This should only happen on a lost context.
495 return;
497 DCHECK_EQ(0u, transform_feedback_varyings_.size());
498 DCHECK_EQ(0u, transform_feedback_varying_max_length_);
500 // |result| comes from GPU process. We consider it trusted data. Therefore,
501 // no need to check for overflows as the GPU side did the checks already.
502 uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader);
503 DCHECK_GE(result.size(), header_size);
504 const TransformFeedbackVaryingsHeader* header =
505 LocalGetAs<const TransformFeedbackVaryingsHeader*>(
506 result, 0, header_size);
507 DCHECK(header);
508 if (header->num_transform_feedback_varyings == 0) {
509 DCHECK_EQ(result.size(), header_size);
510 // TODO(zmo): Here we can't tell if no TransformFeedback varyings are
511 // defined, or the previous link failed.
512 return;
514 transform_feedback_varyings_.resize(header->num_transform_feedback_varyings);
516 uint32_t entry_size = sizeof(TransformFeedbackVaryingInfo) *
517 header->num_transform_feedback_varyings;
518 DCHECK_GE(result.size(), header_size + entry_size);
519 uint32_t data_size = result.size() - header_size - entry_size;
520 DCHECK_LT(0u, data_size);
521 const TransformFeedbackVaryingInfo* entries =
522 LocalGetAs<const TransformFeedbackVaryingInfo*>(
523 result, header_size, entry_size);
524 DCHECK(entries);
525 const char* data = LocalGetAs<const char*>(
526 result, header_size + entry_size, data_size);
527 DCHECK(data);
529 uint32_t size = 0;
530 for (uint32_t ii = 0; ii < header->num_transform_feedback_varyings; ++ii) {
531 transform_feedback_varyings_[ii].size =
532 static_cast<GLsizei>(entries[ii].size);
533 transform_feedback_varyings_[ii].type =
534 static_cast<GLenum>(entries[ii].type);
535 DCHECK_LE(1u, entries[ii].name_length);
536 if (entries[ii].name_length > transform_feedback_varying_max_length_) {
537 transform_feedback_varying_max_length_ = entries[ii].name_length;
539 size += entries[ii].name_length;
540 DCHECK_GE(data_size, size);
541 transform_feedback_varyings_[ii].name =
542 std::string(data, entries[ii].name_length - 1);
543 data += entries[ii].name_length;
545 DCHECK_EQ(data_size, size);
546 cached_es3_transform_feedback_varyings_ = true;
549 bool ProgramInfoManager::Program::IsCached(ProgramInfoType type) const {
550 switch (type) {
551 case kES2:
552 return cached_es2_;
553 case kES3UniformBlocks:
554 return cached_es3_uniform_blocks_;
555 case kES3TransformFeedbackVaryings:
556 return cached_es3_transform_feedback_varyings_;
557 case kES3Uniformsiv:
558 return cached_es3_uniformsiv_;
559 case kNone:
560 return true;
561 default:
562 NOTREACHED();
563 return true;
568 ProgramInfoManager::ProgramInfoManager() {
571 ProgramInfoManager::~ProgramInfoManager() {
574 ProgramInfoManager::Program* ProgramInfoManager::GetProgramInfo(
575 GLES2Implementation* gl, GLuint program, ProgramInfoType type) {
576 lock_.AssertAcquired();
577 ProgramInfoMap::iterator it = program_infos_.find(program);
578 if (it == program_infos_.end()) {
579 return NULL;
581 Program* info = &it->second;
582 if (info->IsCached(type))
583 return info;
585 std::vector<int8> result;
586 switch (type) {
587 case kES2:
589 base::AutoUnlock unlock(lock_);
590 // lock_ can't be held across IPC call or else it may deadlock in
591 // pepper. http://crbug.com/418651
592 gl->GetProgramInfoCHROMIUMHelper(program, &result);
594 info->UpdateES2(result);
595 break;
596 case kES3UniformBlocks:
598 base::AutoUnlock unlock(lock_);
599 // lock_ can't be held across IPC call or else it may deadlock in
600 // pepper. http://crbug.com/418651
601 gl->GetUniformBlocksCHROMIUMHelper(program, &result);
603 info->UpdateES3UniformBlocks(result);
604 break;
605 case kES3TransformFeedbackVaryings:
607 base::AutoUnlock unlock(lock_);
608 // lock_ can't be held across IPC call or else it may deadlock in
609 // pepper. http://crbug.com/418651
610 gl->GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
612 info->UpdateES3TransformFeedbackVaryings(result);
613 break;
614 case kES3Uniformsiv:
616 base::AutoUnlock unlock(lock_);
617 // lock_ can't be held across IPC call or else it may deadlock in
618 // pepper. http://crbug.com/418651
619 gl->GetUniformsES3CHROMIUMHelper(program, &result);
621 info->UpdateES3Uniformsiv(result);
622 break;
623 default:
624 NOTREACHED();
625 return NULL;
627 return info;
630 void ProgramInfoManager::CreateInfo(GLuint program) {
631 base::AutoLock auto_lock(lock_);
632 program_infos_.erase(program);
633 std::pair<ProgramInfoMap::iterator, bool> result =
634 program_infos_.insert(std::make_pair(program, Program()));
636 DCHECK(result.second);
639 void ProgramInfoManager::DeleteInfo(GLuint program) {
640 base::AutoLock auto_lock(lock_);
641 program_infos_.erase(program);
644 bool ProgramInfoManager::GetProgramiv(
645 GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) {
646 base::AutoLock auto_lock(lock_);
647 ProgramInfoType type = kNone;
648 switch (pname) {
649 case GL_ACTIVE_ATTRIBUTES:
650 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
651 case GL_ACTIVE_UNIFORMS:
652 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
653 case GL_LINK_STATUS:
654 type = kES2;
655 break;
656 case GL_ACTIVE_UNIFORM_BLOCKS:
657 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
658 type = kES3UniformBlocks;
659 break;
660 case GL_TRANSFORM_FEEDBACK_VARYINGS:
661 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
662 type = kES3TransformFeedbackVaryings;
663 break;
664 default:
665 return false;
667 Program* info = GetProgramInfo(gl, program, type);
668 if (!info) {
669 return false;
671 return info->GetProgramiv(pname, params);
674 bool ProgramInfoManager::GetActiveUniformsiv(
675 GLES2Implementation* gl, GLuint program, GLsizei count,
676 const GLuint* indices, GLenum pname, GLint* params) {
677 base::AutoLock auto_lock(lock_);
678 ProgramInfoType type = kNone;
679 switch (pname) {
680 case GL_UNIFORM_SIZE:
681 case GL_UNIFORM_TYPE:
682 case GL_UNIFORM_NAME_LENGTH:
683 type = kES2;
684 break;
685 case GL_UNIFORM_BLOCK_INDEX:
686 case GL_UNIFORM_OFFSET:
687 case GL_UNIFORM_ARRAY_STRIDE:
688 case GL_UNIFORM_MATRIX_STRIDE:
689 case GL_UNIFORM_IS_ROW_MAJOR:
690 type = kES3Uniformsiv;
691 break;
692 default:
693 return false;
695 Program* info = GetProgramInfo(gl, program, type);
696 if (info) {
697 return info->GetUniformsiv(count, indices, pname, params);
699 return gl->GetActiveUniformsivHelper(program, count, indices, pname, params);
702 GLint ProgramInfoManager::GetAttribLocation(
703 GLES2Implementation* gl, GLuint program, const char* name) {
705 base::AutoLock auto_lock(lock_);
706 Program* info = GetProgramInfo(gl, program, kES2);
707 if (info) {
708 return info->GetAttribLocation(name);
711 return gl->GetAttribLocationHelper(program, name);
714 GLint ProgramInfoManager::GetUniformLocation(
715 GLES2Implementation* gl, GLuint program, const char* name) {
717 base::AutoLock auto_lock(lock_);
718 Program* info = GetProgramInfo(gl, program, kES2);
719 if (info) {
720 return info->GetUniformLocation(name);
723 return gl->GetUniformLocationHelper(program, name);
726 GLint ProgramInfoManager::GetFragDataLocation(
727 GLES2Implementation* gl, GLuint program, const char* name) {
728 // TODO(zmo): make FragData locations part of the ProgramInfo that are
729 // fetched altogether from the service side. See crbug.com/452104.
731 base::AutoLock auto_lock(lock_);
732 Program* info = GetProgramInfo(gl, program, kNone);
733 if (info) {
734 GLint possible_loc = info->GetFragDataLocation(name);
735 if (possible_loc != -1)
736 return possible_loc;
739 GLint loc = gl->GetFragDataLocationHelper(program, name);
740 if (loc != -1) {
741 base::AutoLock auto_lock(lock_);
742 Program* info = GetProgramInfo(gl, program, kNone);
743 if (info) {
744 info->CacheFragDataLocation(name, loc);
747 return loc;
750 bool ProgramInfoManager::GetActiveAttrib(
751 GLES2Implementation* gl,
752 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
753 GLint* size, GLenum* type, char* name) {
755 base::AutoLock auto_lock(lock_);
756 Program* info = GetProgramInfo(gl, program, kES2);
757 if (info) {
758 const Program::VertexAttrib* attrib_info = info->GetAttribInfo(index);
759 if (attrib_info) {
760 if (size) {
761 *size = attrib_info->size;
763 if (type) {
764 *type = attrib_info->type;
766 if (length || name) {
767 GLsizei max_size = std::min(
768 static_cast<size_t>(bufsize) - 1,
769 std::max(static_cast<size_t>(0), attrib_info->name.size()));
770 if (length) {
771 *length = max_size;
773 if (name && bufsize > 0) {
774 memcpy(name, attrib_info->name.c_str(), max_size);
775 name[max_size] = '\0';
778 return true;
782 return gl->GetActiveAttribHelper(
783 program, index, bufsize, length, size, type, name);
786 bool ProgramInfoManager::GetActiveUniform(
787 GLES2Implementation* gl,
788 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
789 GLint* size, GLenum* type, char* name) {
791 base::AutoLock auto_lock(lock_);
792 Program* info = GetProgramInfo(gl, program, kES2);
793 if (info) {
794 const Program::UniformInfo* uniform_info = info->GetUniformInfo(index);
795 if (uniform_info) {
796 if (size) {
797 *size = uniform_info->size;
799 if (type) {
800 *type = uniform_info->type;
802 if (length || name) {
803 GLsizei max_size = std::min(
804 static_cast<size_t>(bufsize) - 1,
805 std::max(static_cast<size_t>(0), uniform_info->name.size()));
806 if (length) {
807 *length = max_size;
809 if (name && bufsize > 0) {
810 memcpy(name, uniform_info->name.c_str(), max_size);
811 name[max_size] = '\0';
814 return true;
818 return gl->GetActiveUniformHelper(
819 program, index, bufsize, length, size, type, name);
822 GLuint ProgramInfoManager::GetUniformBlockIndex(
823 GLES2Implementation* gl, GLuint program, const char* name) {
825 base::AutoLock auto_lock(lock_);
826 Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
827 if (info) {
828 return info->GetUniformBlockIndex(name);
831 return gl->GetUniformBlockIndexHelper(program, name);
834 bool ProgramInfoManager::GetActiveUniformBlockName(
835 GLES2Implementation* gl, GLuint program, GLuint index,
836 GLsizei buf_size, GLsizei* length, char* name) {
837 DCHECK_LE(0, buf_size);
838 if (!name) {
839 buf_size = 0;
842 base::AutoLock auto_lock(lock_);
843 Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
844 if (info) {
845 const Program::UniformBlock* uniform_block = info->GetUniformBlock(index);
846 if (uniform_block) {
847 if (buf_size == 0) {
848 if (length) {
849 *length = 0;
851 } else if (length || name) {
852 GLsizei max_size = std::min(
853 buf_size - 1, static_cast<GLsizei>(uniform_block->name.size()));
854 if (length) {
855 *length = max_size;
857 if (name) {
858 memcpy(name, uniform_block->name.data(), max_size);
859 name[max_size] = '\0';
862 return true;
866 return gl->GetActiveUniformBlockNameHelper(
867 program, index, buf_size, length, name);
870 bool ProgramInfoManager::GetActiveUniformBlockiv(
871 GLES2Implementation* gl, GLuint program, GLuint index,
872 GLenum pname, GLint* params) {
874 base::AutoLock auto_lock(lock_);
875 Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
876 if (info) {
877 const Program::UniformBlock* uniform_block = info->GetUniformBlock(index);
878 bool valid_pname;
879 switch (pname) {
880 case GL_UNIFORM_BLOCK_BINDING:
881 case GL_UNIFORM_BLOCK_DATA_SIZE:
882 case GL_UNIFORM_BLOCK_NAME_LENGTH:
883 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
884 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
885 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
886 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
887 valid_pname = true;
888 break;
889 default:
890 valid_pname = false;
891 break;
893 if (uniform_block && valid_pname && params) {
894 switch (pname) {
895 case GL_UNIFORM_BLOCK_BINDING:
896 *params = static_cast<GLint>(uniform_block->binding);
897 break;
898 case GL_UNIFORM_BLOCK_DATA_SIZE:
899 *params = static_cast<GLint>(uniform_block->data_size);
900 break;
901 case GL_UNIFORM_BLOCK_NAME_LENGTH:
902 *params = static_cast<GLint>(uniform_block->name.size()) + 1;
903 break;
904 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
905 *params = static_cast<GLint>(
906 uniform_block->active_uniform_indices.size());
907 break;
908 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
909 for (size_t ii = 0;
910 ii < uniform_block->active_uniform_indices.size(); ++ii) {
911 params[ii] = static_cast<GLint>(
912 uniform_block->active_uniform_indices[ii]);
914 break;
915 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
916 *params = static_cast<GLint>(
917 uniform_block->referenced_by_vertex_shader);
918 break;
919 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
920 *params = static_cast<GLint>(
921 uniform_block->referenced_by_fragment_shader);
922 break;
923 default:
924 NOTREACHED();
926 return true;
930 return gl->GetActiveUniformBlockivHelper(program, index, pname, params);
933 void ProgramInfoManager::UniformBlockBinding(
934 GLES2Implementation* gl, GLuint program, GLuint index, GLuint binding) {
935 GLuint max_bindings =
936 static_cast<GLuint>(gl->capabilities().max_uniform_buffer_bindings);
937 if (binding < max_bindings) {
938 base::AutoLock auto_lock(lock_);
939 // If UniformBlock info haven't been cached yet, skip updating the binding.
940 Program* info = GetProgramInfo(gl, program, kNone);
941 if (info) {
942 info->UniformBlockBinding(index, binding);
947 bool ProgramInfoManager::GetTransformFeedbackVarying(
948 GLES2Implementation* gl, GLuint program, GLuint index, GLsizei bufsize,
949 GLsizei* length, GLsizei* size, GLenum* type, char* name) {
951 base::AutoLock auto_lock(lock_);
952 Program* info = GetProgramInfo(gl, program, kES3TransformFeedbackVaryings);
953 if (info) {
954 const Program::TransformFeedbackVarying* varying =
955 info->GetTransformFeedbackVarying(index);
956 if (varying) {
957 if (size) {
958 *size = varying->size;
960 if (type) {
961 *type = varying->type;
963 if (length || name) {
964 GLsizei max_size = std::min(
965 bufsize - 1, static_cast<GLsizei>(varying->name.size()));
966 if (length) {
967 *length = static_cast<GLsizei>(max_size);
969 if (name && bufsize > 0) {
970 memcpy(name, varying->name.c_str(), max_size);
971 name[max_size] = '\0';
974 return true;
978 return gl->GetTransformFeedbackVaryingHelper(
979 program, index, bufsize, length, size, type, name);
982 bool ProgramInfoManager::GetUniformIndices(GLES2Implementation* gl,
983 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
985 base::AutoLock auto_lock(lock_);
986 Program* info = GetProgramInfo(gl, program, kES2);
987 if (info) {
988 DCHECK_LT(0, count);
989 DCHECK(names && indices);
990 for (GLsizei ii = 0; ii < count; ++ii) {
991 indices[ii] = info->GetUniformIndex(names[ii]);
993 return true;
996 return gl->GetUniformIndicesHelper(program, count, names, indices);
999 } // namespace gles2
1000 } // namespace gpu