Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / gpu / command_buffer / client / program_info_manager.cc
blob6d33d858835c1501d203c6a94d9590ecc97062ae
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 transform_feedback_buffer_mode_(0),
88 cached_es3_uniformsiv_(false) {
91 ProgramInfoManager::Program::~Program() {
94 // TODO(gman): Add a faster lookup.
95 GLint ProgramInfoManager::Program::GetAttribLocation(
96 const std::string& name) const {
97 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
98 const VertexAttrib& info = attrib_infos_[ii];
99 if (info.name == name) {
100 return info.location;
103 return -1;
106 const ProgramInfoManager::Program::VertexAttrib*
107 ProgramInfoManager::Program::GetAttribInfo(GLint index) const {
108 return (static_cast<size_t>(index) < attrib_infos_.size()) ?
109 &attrib_infos_[index] : NULL;
112 const ProgramInfoManager::Program::UniformInfo*
113 ProgramInfoManager::Program::GetUniformInfo(GLint index) const {
114 return (static_cast<size_t>(index) < uniform_infos_.size()) ?
115 &uniform_infos_[index] : NULL;
118 const ProgramInfoManager::Program::UniformBlock*
119 ProgramInfoManager::Program::GetUniformBlock(GLuint index) const {
120 return (index < uniform_blocks_.size()) ? &uniform_blocks_[index] : NULL;
123 GLint ProgramInfoManager::Program::GetUniformLocation(
124 const std::string& name) const {
125 bool getting_array_location = false;
126 size_t open_pos = std::string::npos;
127 int index = 0;
128 if (!GLES2Util::ParseUniformName(
129 name, &open_pos, &index, &getting_array_location)) {
130 return -1;
132 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
133 const UniformInfo& info = uniform_infos_[ii];
134 if (info.name == name ||
135 (info.is_array &&
136 info.name.compare(0, info.name.size() - 3, name) == 0)) {
137 return info.element_locations[0];
138 } else if (getting_array_location && info.is_array) {
139 // Look for an array specification.
140 size_t open_pos_2 = info.name.find_last_of('[');
141 if (open_pos_2 == open_pos &&
142 name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
143 if (index >= 0 && index < info.size) {
144 return info.element_locations[index];
149 return -1;
152 GLuint ProgramInfoManager::Program::GetUniformIndex(
153 const std::string& name) const {
154 // TODO(zmo): Maybe build a hashed_map for faster lookup.
155 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
156 const UniformInfo& info = uniform_infos_[ii];
157 // For an array, either "var" or "var[0]" is considered as a match.
158 // See "OpenGL ES 3.0.0, Section 2.11.3 Program Objects."
159 if (info.name == name ||
160 (info.is_array &&
161 info.name.compare(0, info.name.size() - 3, name) == 0)) {
162 return ii;
165 return GL_INVALID_INDEX;
168 GLint ProgramInfoManager::Program::GetFragDataLocation(
169 const std::string& name) const {
170 base::hash_map<std::string, GLint>::const_iterator iter =
171 frag_data_locations_.find(name);
172 if (iter == frag_data_locations_.end())
173 return -1;
174 return iter->second;
177 void ProgramInfoManager::Program::CacheFragDataLocation(
178 const std::string& name, GLint loc) {
179 frag_data_locations_[name] = loc;
182 bool ProgramInfoManager::Program::GetProgramiv(
183 GLenum pname, GLint* params) {
184 switch (pname) {
185 case GL_LINK_STATUS:
186 *params = static_cast<GLint>(link_status_);
187 return true;
188 case GL_ACTIVE_ATTRIBUTES:
189 *params = static_cast<GLint>(attrib_infos_.size());
190 return true;
191 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
192 *params = static_cast<GLint>(max_attrib_name_length_);
193 return true;
194 case GL_ACTIVE_UNIFORMS:
195 *params = static_cast<GLint>(uniform_infos_.size());
196 return true;
197 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
198 *params = static_cast<GLint>(max_uniform_name_length_);
199 return true;
200 case GL_ACTIVE_UNIFORM_BLOCKS:
201 *params = static_cast<GLint>(uniform_blocks_.size());
202 return true;
203 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
204 *params = static_cast<GLint>(active_uniform_block_max_name_length_);
205 return true;
206 case GL_TRANSFORM_FEEDBACK_VARYINGS:
207 *params = static_cast<GLint>(transform_feedback_varyings_.size());
208 return true;
209 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
210 *params = static_cast<GLint>(transform_feedback_varying_max_length_);
211 return true;
212 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
213 *params = static_cast<GLint>(transform_feedback_buffer_mode_);
214 return true;
215 default:
216 NOTREACHED();
217 break;
219 return false;
222 GLuint ProgramInfoManager::Program::GetUniformBlockIndex(
223 const std::string& name) const {
224 for (size_t ii = 0; ii < uniform_blocks_.size(); ++ii) {
225 if (uniform_blocks_[ii].name == name) {
226 return static_cast<GLuint>(ii);
229 return GL_INVALID_INDEX;
232 void ProgramInfoManager::Program::UniformBlockBinding(
233 GLuint index , GLuint binding) {
234 if (index < uniform_blocks_.size()) {
235 uniform_blocks_[index].binding = binding;
239 const ProgramInfoManager::Program::TransformFeedbackVarying*
240 ProgramInfoManager::Program::GetTransformFeedbackVarying(GLuint index) const {
241 return (index < transform_feedback_varyings_.size()) ?
242 &transform_feedback_varyings_[index] : NULL;
245 bool ProgramInfoManager::Program::GetUniformsiv(
246 GLsizei count, const GLuint* indices, GLenum pname, GLint* params) {
247 if (count == 0) {
248 // At this point, pname has already been validated.
249 return true;
251 DCHECK(count > 0 && indices);
252 size_t num_uniforms = uniform_infos_.size();
253 if (num_uniforms == 0) {
254 num_uniforms = uniforms_es3_.size();
256 if (static_cast<size_t>(count) > num_uniforms) {
257 return false;
259 for (GLsizei ii = 0; ii < count; ++ii) {
260 if (indices[ii] >= num_uniforms) {
261 return false;
264 if (!params) {
265 return true;
267 switch (pname) {
268 case GL_UNIFORM_SIZE:
269 DCHECK_EQ(num_uniforms, uniform_infos_.size());
270 for (GLsizei ii = 0; ii < count; ++ii) {
271 params[ii] = static_cast<GLint>(uniform_infos_[indices[ii]].size);
273 return true;
274 case GL_UNIFORM_TYPE:
275 DCHECK_EQ(num_uniforms, uniform_infos_.size());
276 for (GLsizei ii = 0; ii < count; ++ii) {
277 params[ii] = static_cast<GLint>(uniform_infos_[indices[ii]].type);
279 return true;
280 case GL_UNIFORM_NAME_LENGTH:
281 DCHECK_EQ(num_uniforms, uniform_infos_.size());
282 for (GLsizei ii = 0; ii < count; ++ii) {
283 params[ii] = static_cast<GLint>(
284 uniform_infos_[indices[ii]].name.length() + 1);
286 return true;
287 case GL_UNIFORM_BLOCK_INDEX:
288 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
289 for (GLsizei ii = 0; ii < count; ++ii) {
290 params[ii] = uniforms_es3_[indices[ii]].block_index;
292 return true;
293 case GL_UNIFORM_OFFSET:
294 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
295 for (GLsizei ii = 0; ii < count; ++ii) {
296 params[ii] = uniforms_es3_[indices[ii]].offset;
298 return true;
299 case GL_UNIFORM_ARRAY_STRIDE:
300 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
301 for (GLsizei ii = 0; ii < count; ++ii) {
302 params[ii] = uniforms_es3_[indices[ii]].array_stride;
304 return true;
305 case GL_UNIFORM_MATRIX_STRIDE:
306 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
307 for (GLsizei ii = 0; ii < count; ++ii) {
308 params[ii] = uniforms_es3_[indices[ii]].matrix_stride;
310 return true;
311 case GL_UNIFORM_IS_ROW_MAJOR:
312 DCHECK_EQ(num_uniforms, uniforms_es3_.size());
313 for (GLsizei ii = 0; ii < count; ++ii) {
314 params[ii] = uniforms_es3_[indices[ii]].is_row_major;
316 return true;
317 default:
318 NOTREACHED();
319 break;
321 return false;
324 void ProgramInfoManager::Program::UpdateES2(const std::vector<int8>& result) {
325 if (cached_es2_) {
326 return;
328 if (result.empty()) {
329 // This should only happen on a lost context.
330 return;
332 DCHECK_GE(result.size(), sizeof(ProgramInfoHeader));
333 const ProgramInfoHeader* header = LocalGetAs<const ProgramInfoHeader*>(
334 result, 0, sizeof(header));
335 link_status_ = header->link_status != 0;
336 if (!link_status_) {
337 return;
339 DCHECK_EQ(0u, attrib_infos_.size());
340 DCHECK_EQ(0u, uniform_infos_.size());
341 DCHECK_EQ(0, max_attrib_name_length_);
342 DCHECK_EQ(0, max_uniform_name_length_);
343 const ProgramInput* inputs = LocalGetAs<const ProgramInput*>(
344 result, sizeof(*header),
345 sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms));
346 const ProgramInput* input = inputs;
347 for (uint32 ii = 0; ii < header->num_attribs; ++ii) {
348 const int32* location = LocalGetAs<const int32*>(
349 result, input->location_offset, sizeof(int32));
350 const char* name_buf = LocalGetAs<const char*>(
351 result, input->name_offset, input->name_length);
352 std::string name(name_buf, input->name_length);
353 attrib_infos_.push_back(
354 VertexAttrib(input->size, input->type, name, *location));
355 max_attrib_name_length_ = std::max(
356 static_cast<GLsizei>(name.size() + 1), max_attrib_name_length_);
357 ++input;
359 for (uint32 ii = 0; ii < header->num_uniforms; ++ii) {
360 const int32* locations = LocalGetAs<const int32*>(
361 result, input->location_offset, sizeof(int32) * input->size);
362 const char* name_buf = LocalGetAs<const char*>(
363 result, input->name_offset, input->name_length);
364 std::string name(name_buf, input->name_length);
365 UniformInfo info(input->size, input->type, name);
366 max_uniform_name_length_ = std::max(
367 static_cast<GLsizei>(name.size() + 1), max_uniform_name_length_);
368 for (int32 jj = 0; jj < input->size; ++jj) {
369 info.element_locations.push_back(locations[jj]);
371 uniform_infos_.push_back(info);
372 ++input;
374 DCHECK_EQ(header->num_attribs + header->num_uniforms,
375 static_cast<uint32>(input - inputs));
376 cached_es2_ = true;
379 void ProgramInfoManager::Program::UpdateES3UniformBlocks(
380 const std::vector<int8>& result) {
381 if (cached_es3_uniform_blocks_) {
382 return;
384 if (result.empty()) {
385 // This should only happen on a lost context.
386 return;
388 DCHECK_EQ(0u, uniform_blocks_.size());
389 DCHECK_EQ(0u, active_uniform_block_max_name_length_);
391 // |result| comes from GPU process. We consider it trusted data. Therefore,
392 // no need to check for overflows as the GPU side did the checks already.
393 uint32_t header_size = sizeof(UniformBlocksHeader);
394 DCHECK_GE(result.size(), header_size);
395 const UniformBlocksHeader* header = LocalGetAs<const UniformBlocksHeader*>(
396 result, 0, header_size);
397 DCHECK(header);
398 if (header->num_uniform_blocks == 0) {
399 DCHECK_EQ(result.size(), header_size);
400 // TODO(zmo): Here we can't tell if no uniform blocks are defined, or
401 // the previous link failed.
402 return;
404 uniform_blocks_.resize(header->num_uniform_blocks);
406 uint32_t entry_size = sizeof(UniformBlockInfo) * header->num_uniform_blocks;
407 DCHECK_GE(result.size(), header_size + entry_size);
408 uint32_t data_size = result.size() - header_size - entry_size;
409 DCHECK_LT(0u, data_size);
410 const UniformBlockInfo* entries = LocalGetAs<const UniformBlockInfo*>(
411 result, header_size, entry_size);
412 DCHECK(entries);
413 const char* data = LocalGetAs<const char*>(
414 result, header_size + entry_size, data_size);
415 DCHECK(data);
417 uint32_t size = 0;
418 for (uint32_t ii = 0; ii < header->num_uniform_blocks; ++ii) {
419 uniform_blocks_[ii].binding = static_cast<GLuint>(entries[ii].binding);
420 uniform_blocks_[ii].data_size = static_cast<GLuint>(entries[ii].data_size);
421 uniform_blocks_[ii].active_uniform_indices.resize(
422 entries[ii].active_uniforms);
423 uniform_blocks_[ii].referenced_by_vertex_shader = static_cast<GLboolean>(
424 entries[ii].referenced_by_vertex_shader);
425 uniform_blocks_[ii].referenced_by_fragment_shader = static_cast<GLboolean>(
426 entries[ii].referenced_by_fragment_shader);
427 // Uniform block names can't be empty strings.
428 DCHECK_LT(1u, entries[ii].name_length);
429 if (entries[ii].name_length > active_uniform_block_max_name_length_) {
430 active_uniform_block_max_name_length_ = entries[ii].name_length;
432 size += entries[ii].name_length;
433 DCHECK_GE(data_size, size);
434 uniform_blocks_[ii].name = std::string(data, entries[ii].name_length - 1);
435 data += entries[ii].name_length;
436 size += entries[ii].active_uniforms * sizeof(uint32_t);
437 DCHECK_GE(data_size, size);
438 const uint32_t* indices = reinterpret_cast<const uint32_t*>(data);
439 for (uint32_t uu = 0; uu < entries[ii].active_uniforms; ++uu) {
440 uniform_blocks_[ii].active_uniform_indices[uu] =
441 static_cast<GLuint>(indices[uu]);
443 indices += entries[ii].active_uniforms;
444 data = reinterpret_cast<const char*>(indices);
446 DCHECK_EQ(data_size, size);
447 cached_es3_uniform_blocks_ = true;
450 void ProgramInfoManager::Program::UpdateES3Uniformsiv(
451 const std::vector<int8>& result) {
452 if (cached_es3_uniformsiv_) {
453 return;
455 if (result.empty()) {
456 // This should only happen on a lost context.
457 return;
459 DCHECK_EQ(0u, uniforms_es3_.size());
461 // |result| comes from GPU process. We consider it trusted data. Therefore,
462 // no need to check for overflows as the GPU side did the checks already.
463 uint32_t header_size = sizeof(UniformsES3Header);
464 DCHECK_GE(result.size(), header_size);
465 const UniformsES3Header* header = LocalGetAs<const UniformsES3Header*>(
466 result, 0, header_size);
467 DCHECK(header);
468 if (header->num_uniforms == 0) {
469 DCHECK_EQ(result.size(), header_size);
470 // TODO(zmo): Here we can't tell if no uniforms are defined, or
471 // the previous link failed.
472 return;
474 uniforms_es3_.resize(header->num_uniforms);
476 uint32_t entry_size = sizeof(UniformES3Info) * header->num_uniforms;
477 DCHECK_EQ(result.size(), header_size + entry_size);
478 const UniformES3Info* entries = LocalGetAs<const UniformES3Info*>(
479 result, header_size, entry_size);
480 DCHECK(entries);
482 for (uint32_t ii = 0; ii < header->num_uniforms; ++ii) {
483 uniforms_es3_[ii].block_index = entries[ii].block_index;
484 uniforms_es3_[ii].offset = entries[ii].offset;
485 uniforms_es3_[ii].array_stride = entries[ii].array_stride;
486 uniforms_es3_[ii].matrix_stride = entries[ii].matrix_stride;
487 uniforms_es3_[ii].is_row_major = entries[ii].is_row_major;
489 cached_es3_uniformsiv_ = true;
492 void ProgramInfoManager::Program::UpdateES3TransformFeedbackVaryings(
493 const std::vector<int8>& result) {
494 if (cached_es3_transform_feedback_varyings_) {
495 return;
497 if (result.empty()) {
498 // This should only happen on a lost context.
499 return;
501 DCHECK_EQ(0u, transform_feedback_buffer_mode_);
502 DCHECK_EQ(0u, transform_feedback_varyings_.size());
503 DCHECK_EQ(0u, transform_feedback_varying_max_length_);
505 // |result| comes from GPU process. We consider it trusted data. Therefore,
506 // no need to check for overflows as the GPU side did the checks already.
507 uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader);
508 DCHECK_GE(result.size(), header_size);
509 const TransformFeedbackVaryingsHeader* header =
510 LocalGetAs<const TransformFeedbackVaryingsHeader*>(
511 result, 0, header_size);
512 DCHECK(header);
513 transform_feedback_buffer_mode_ = header->transform_feedback_buffer_mode;
514 if (header->num_transform_feedback_varyings == 0) {
515 DCHECK_EQ(result.size(), header_size);
516 // TODO(zmo): Here we can't tell if no TransformFeedback varyings are
517 // defined, or the previous link failed.
518 return;
520 transform_feedback_varyings_.resize(header->num_transform_feedback_varyings);
522 uint32_t entry_size = sizeof(TransformFeedbackVaryingInfo) *
523 header->num_transform_feedback_varyings;
524 DCHECK_GE(result.size(), header_size + entry_size);
525 uint32_t data_size = result.size() - header_size - entry_size;
526 DCHECK_LT(0u, data_size);
527 const TransformFeedbackVaryingInfo* entries =
528 LocalGetAs<const TransformFeedbackVaryingInfo*>(
529 result, header_size, entry_size);
530 DCHECK(entries);
531 const char* data = LocalGetAs<const char*>(
532 result, header_size + entry_size, data_size);
533 DCHECK(data);
535 uint32_t size = 0;
536 for (uint32_t ii = 0; ii < header->num_transform_feedback_varyings; ++ii) {
537 transform_feedback_varyings_[ii].size =
538 static_cast<GLsizei>(entries[ii].size);
539 transform_feedback_varyings_[ii].type =
540 static_cast<GLenum>(entries[ii].type);
541 DCHECK_LE(1u, entries[ii].name_length);
542 if (entries[ii].name_length > transform_feedback_varying_max_length_) {
543 transform_feedback_varying_max_length_ = entries[ii].name_length;
545 size += entries[ii].name_length;
546 DCHECK_GE(data_size, size);
547 transform_feedback_varyings_[ii].name =
548 std::string(data, entries[ii].name_length - 1);
549 data += entries[ii].name_length;
551 DCHECK_EQ(data_size, size);
552 cached_es3_transform_feedback_varyings_ = true;
555 bool ProgramInfoManager::Program::IsCached(ProgramInfoType type) const {
556 switch (type) {
557 case kES2:
558 return cached_es2_;
559 case kES3UniformBlocks:
560 return cached_es3_uniform_blocks_;
561 case kES3TransformFeedbackVaryings:
562 return cached_es3_transform_feedback_varyings_;
563 case kES3Uniformsiv:
564 return cached_es3_uniformsiv_;
565 case kNone:
566 return true;
567 default:
568 NOTREACHED();
569 return true;
574 ProgramInfoManager::ProgramInfoManager() {
577 ProgramInfoManager::~ProgramInfoManager() {
580 ProgramInfoManager::Program* ProgramInfoManager::GetProgramInfo(
581 GLES2Implementation* gl, GLuint program, ProgramInfoType type) {
582 lock_.AssertAcquired();
583 ProgramInfoMap::iterator it = program_infos_.find(program);
584 if (it == program_infos_.end()) {
585 return NULL;
587 Program* info = &it->second;
588 if (info->IsCached(type))
589 return info;
591 std::vector<int8> result;
592 switch (type) {
593 case kES2:
595 base::AutoUnlock unlock(lock_);
596 // lock_ can't be held across IPC call or else it may deadlock in
597 // pepper. http://crbug.com/418651
598 gl->GetProgramInfoCHROMIUMHelper(program, &result);
600 info->UpdateES2(result);
601 break;
602 case kES3UniformBlocks:
604 base::AutoUnlock unlock(lock_);
605 // lock_ can't be held across IPC call or else it may deadlock in
606 // pepper. http://crbug.com/418651
607 gl->GetUniformBlocksCHROMIUMHelper(program, &result);
609 info->UpdateES3UniformBlocks(result);
610 break;
611 case kES3TransformFeedbackVaryings:
613 base::AutoUnlock unlock(lock_);
614 // lock_ can't be held across IPC call or else it may deadlock in
615 // pepper. http://crbug.com/418651
616 gl->GetTransformFeedbackVaryingsCHROMIUMHelper(program, &result);
618 info->UpdateES3TransformFeedbackVaryings(result);
619 break;
620 case kES3Uniformsiv:
622 base::AutoUnlock unlock(lock_);
623 // lock_ can't be held across IPC call or else it may deadlock in
624 // pepper. http://crbug.com/418651
625 gl->GetUniformsES3CHROMIUMHelper(program, &result);
627 info->UpdateES3Uniformsiv(result);
628 break;
629 default:
630 NOTREACHED();
631 return NULL;
633 return info;
636 void ProgramInfoManager::CreateInfo(GLuint program) {
637 base::AutoLock auto_lock(lock_);
638 program_infos_.erase(program);
639 std::pair<ProgramInfoMap::iterator, bool> result =
640 program_infos_.insert(std::make_pair(program, Program()));
642 DCHECK(result.second);
645 void ProgramInfoManager::DeleteInfo(GLuint program) {
646 base::AutoLock auto_lock(lock_);
647 program_infos_.erase(program);
650 bool ProgramInfoManager::GetProgramiv(
651 GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) {
652 base::AutoLock auto_lock(lock_);
653 ProgramInfoType type = kNone;
654 switch (pname) {
655 case GL_ACTIVE_ATTRIBUTES:
656 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
657 case GL_ACTIVE_UNIFORMS:
658 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
659 case GL_LINK_STATUS:
660 type = kES2;
661 break;
662 case GL_ACTIVE_UNIFORM_BLOCKS:
663 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
664 type = kES3UniformBlocks;
665 break;
666 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
667 case GL_TRANSFORM_FEEDBACK_VARYINGS:
668 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
669 type = kES3TransformFeedbackVaryings;
670 break;
671 default:
672 return false;
674 Program* info = GetProgramInfo(gl, program, type);
675 if (!info) {
676 return false;
678 return info->GetProgramiv(pname, params);
681 bool ProgramInfoManager::GetActiveUniformsiv(
682 GLES2Implementation* gl, GLuint program, GLsizei count,
683 const GLuint* indices, GLenum pname, GLint* params) {
684 base::AutoLock auto_lock(lock_);
685 ProgramInfoType type = kNone;
686 switch (pname) {
687 case GL_UNIFORM_SIZE:
688 case GL_UNIFORM_TYPE:
689 case GL_UNIFORM_NAME_LENGTH:
690 type = kES2;
691 break;
692 case GL_UNIFORM_BLOCK_INDEX:
693 case GL_UNIFORM_OFFSET:
694 case GL_UNIFORM_ARRAY_STRIDE:
695 case GL_UNIFORM_MATRIX_STRIDE:
696 case GL_UNIFORM_IS_ROW_MAJOR:
697 type = kES3Uniformsiv;
698 break;
699 default:
700 return false;
702 Program* info = GetProgramInfo(gl, program, type);
703 if (info) {
704 return info->GetUniformsiv(count, indices, pname, params);
706 return gl->GetActiveUniformsivHelper(program, count, indices, pname, params);
709 GLint ProgramInfoManager::GetAttribLocation(
710 GLES2Implementation* gl, GLuint program, const char* name) {
712 base::AutoLock auto_lock(lock_);
713 Program* info = GetProgramInfo(gl, program, kES2);
714 if (info) {
715 return info->GetAttribLocation(name);
718 return gl->GetAttribLocationHelper(program, name);
721 GLint ProgramInfoManager::GetUniformLocation(
722 GLES2Implementation* gl, GLuint program, const char* name) {
724 base::AutoLock auto_lock(lock_);
725 Program* info = GetProgramInfo(gl, program, kES2);
726 if (info) {
727 return info->GetUniformLocation(name);
730 return gl->GetUniformLocationHelper(program, name);
733 GLint ProgramInfoManager::GetFragDataLocation(
734 GLES2Implementation* gl, GLuint program, const char* name) {
735 // TODO(zmo): make FragData locations part of the ProgramInfo that are
736 // fetched altogether from the service side. See crbug.com/452104.
738 base::AutoLock auto_lock(lock_);
739 Program* info = GetProgramInfo(gl, program, kNone);
740 if (info) {
741 GLint possible_loc = info->GetFragDataLocation(name);
742 if (possible_loc != -1)
743 return possible_loc;
746 GLint loc = gl->GetFragDataLocationHelper(program, name);
747 if (loc != -1) {
748 base::AutoLock auto_lock(lock_);
749 Program* info = GetProgramInfo(gl, program, kNone);
750 if (info) {
751 info->CacheFragDataLocation(name, loc);
754 return loc;
757 bool ProgramInfoManager::GetActiveAttrib(
758 GLES2Implementation* gl,
759 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
760 GLint* size, GLenum* type, char* name) {
762 base::AutoLock auto_lock(lock_);
763 Program* info = GetProgramInfo(gl, program, kES2);
764 if (info) {
765 const Program::VertexAttrib* attrib_info = info->GetAttribInfo(index);
766 if (attrib_info) {
767 if (size) {
768 *size = attrib_info->size;
770 if (type) {
771 *type = attrib_info->type;
773 if (length || name) {
774 GLsizei max_size = std::min(
775 static_cast<size_t>(bufsize) - 1,
776 std::max(static_cast<size_t>(0), attrib_info->name.size()));
777 if (length) {
778 *length = max_size;
780 if (name && bufsize > 0) {
781 memcpy(name, attrib_info->name.c_str(), max_size);
782 name[max_size] = '\0';
785 return true;
789 return gl->GetActiveAttribHelper(
790 program, index, bufsize, length, size, type, name);
793 bool ProgramInfoManager::GetActiveUniform(
794 GLES2Implementation* gl,
795 GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
796 GLint* size, GLenum* type, char* name) {
798 base::AutoLock auto_lock(lock_);
799 Program* info = GetProgramInfo(gl, program, kES2);
800 if (info) {
801 const Program::UniformInfo* uniform_info = info->GetUniformInfo(index);
802 if (uniform_info) {
803 if (size) {
804 *size = uniform_info->size;
806 if (type) {
807 *type = uniform_info->type;
809 if (length || name) {
810 GLsizei max_size = std::min(
811 static_cast<size_t>(bufsize) - 1,
812 std::max(static_cast<size_t>(0), uniform_info->name.size()));
813 if (length) {
814 *length = max_size;
816 if (name && bufsize > 0) {
817 memcpy(name, uniform_info->name.c_str(), max_size);
818 name[max_size] = '\0';
821 return true;
825 return gl->GetActiveUniformHelper(
826 program, index, bufsize, length, size, type, name);
829 GLuint ProgramInfoManager::GetUniformBlockIndex(
830 GLES2Implementation* gl, GLuint program, const char* name) {
832 base::AutoLock auto_lock(lock_);
833 Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
834 if (info) {
835 return info->GetUniformBlockIndex(name);
838 return gl->GetUniformBlockIndexHelper(program, name);
841 bool ProgramInfoManager::GetActiveUniformBlockName(
842 GLES2Implementation* gl, GLuint program, GLuint index,
843 GLsizei buf_size, GLsizei* length, char* name) {
844 DCHECK_LE(0, buf_size);
845 if (!name) {
846 buf_size = 0;
849 base::AutoLock auto_lock(lock_);
850 Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
851 if (info) {
852 const Program::UniformBlock* uniform_block = info->GetUniformBlock(index);
853 if (uniform_block) {
854 if (buf_size == 0) {
855 if (length) {
856 *length = 0;
858 } else if (length || name) {
859 GLsizei max_size = std::min(
860 buf_size - 1, static_cast<GLsizei>(uniform_block->name.size()));
861 if (length) {
862 *length = max_size;
864 if (name) {
865 memcpy(name, uniform_block->name.data(), max_size);
866 name[max_size] = '\0';
869 return true;
873 return gl->GetActiveUniformBlockNameHelper(
874 program, index, buf_size, length, name);
877 bool ProgramInfoManager::GetActiveUniformBlockiv(
878 GLES2Implementation* gl, GLuint program, GLuint index,
879 GLenum pname, GLint* params) {
881 base::AutoLock auto_lock(lock_);
882 Program* info = GetProgramInfo(gl, program, kES3UniformBlocks);
883 if (info) {
884 const Program::UniformBlock* uniform_block = info->GetUniformBlock(index);
885 bool valid_pname;
886 switch (pname) {
887 case GL_UNIFORM_BLOCK_BINDING:
888 case GL_UNIFORM_BLOCK_DATA_SIZE:
889 case GL_UNIFORM_BLOCK_NAME_LENGTH:
890 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
891 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
892 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
893 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
894 valid_pname = true;
895 break;
896 default:
897 valid_pname = false;
898 break;
900 if (uniform_block && valid_pname && params) {
901 switch (pname) {
902 case GL_UNIFORM_BLOCK_BINDING:
903 *params = static_cast<GLint>(uniform_block->binding);
904 break;
905 case GL_UNIFORM_BLOCK_DATA_SIZE:
906 *params = static_cast<GLint>(uniform_block->data_size);
907 break;
908 case GL_UNIFORM_BLOCK_NAME_LENGTH:
909 *params = static_cast<GLint>(uniform_block->name.size()) + 1;
910 break;
911 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
912 *params = static_cast<GLint>(
913 uniform_block->active_uniform_indices.size());
914 break;
915 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
916 for (size_t ii = 0;
917 ii < uniform_block->active_uniform_indices.size(); ++ii) {
918 params[ii] = static_cast<GLint>(
919 uniform_block->active_uniform_indices[ii]);
921 break;
922 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
923 *params = static_cast<GLint>(
924 uniform_block->referenced_by_vertex_shader);
925 break;
926 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
927 *params = static_cast<GLint>(
928 uniform_block->referenced_by_fragment_shader);
929 break;
930 default:
931 NOTREACHED();
933 return true;
937 return gl->GetActiveUniformBlockivHelper(program, index, pname, params);
940 void ProgramInfoManager::UniformBlockBinding(
941 GLES2Implementation* gl, GLuint program, GLuint index, GLuint binding) {
942 GLuint max_bindings =
943 static_cast<GLuint>(gl->capabilities().max_uniform_buffer_bindings);
944 if (binding < max_bindings) {
945 base::AutoLock auto_lock(lock_);
946 // If UniformBlock info haven't been cached yet, skip updating the binding.
947 Program* info = GetProgramInfo(gl, program, kNone);
948 if (info) {
949 info->UniformBlockBinding(index, binding);
954 bool ProgramInfoManager::GetTransformFeedbackVarying(
955 GLES2Implementation* gl, GLuint program, GLuint index, GLsizei bufsize,
956 GLsizei* length, GLsizei* size, GLenum* type, char* name) {
958 base::AutoLock auto_lock(lock_);
959 Program* info = GetProgramInfo(gl, program, kES3TransformFeedbackVaryings);
960 if (info) {
961 const Program::TransformFeedbackVarying* varying =
962 info->GetTransformFeedbackVarying(index);
963 if (varying) {
964 if (size) {
965 *size = varying->size;
967 if (type) {
968 *type = varying->type;
970 if (length || name) {
971 GLsizei max_size = std::min(
972 bufsize - 1, static_cast<GLsizei>(varying->name.size()));
973 if (length) {
974 *length = static_cast<GLsizei>(max_size);
976 if (name && bufsize > 0) {
977 memcpy(name, varying->name.c_str(), max_size);
978 name[max_size] = '\0';
981 return true;
985 return gl->GetTransformFeedbackVaryingHelper(
986 program, index, bufsize, length, size, type, name);
989 bool ProgramInfoManager::GetUniformIndices(GLES2Implementation* gl,
990 GLuint program, GLsizei count, const char* const* names, GLuint* indices) {
992 base::AutoLock auto_lock(lock_);
993 Program* info = GetProgramInfo(gl, program, kES2);
994 if (info) {
995 DCHECK_LT(0, count);
996 DCHECK(names && indices);
997 for (GLsizei ii = 0; ii < count; ++ii) {
998 indices[ii] = info->GetUniformIndex(names[ii]);
1000 return true;
1003 return gl->GetUniformIndicesHelper(program, count, names, indices);
1006 } // namespace gles2
1007 } // namespace gpu