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. 4 5 #include "gpu/command_buffer/service/program_manager.h" 6 7 #include <algorithm> 8 #include <set> 9 #include <utility> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/command_line.h" 14 #include "base/logging.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/metrics/histogram.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "base/time/time.h" 19 #include "gpu/command_buffer/common/gles2_cmd_format.h" 20 #include "gpu/command_buffer/common/gles2_cmd_utils.h" 21 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" 22 #include "gpu/command_buffer/service/gpu_switches.h" 23 #include "gpu/command_buffer/service/program_cache.h" 24 #include "gpu/command_buffer/service/shader_manager.h" 25 #include "gpu/command_buffer/service/shader_translator.h" 26 #include "third_party/re2/re2/re2.h" 27 28 using base::TimeDelta; 29 using base::TimeTicks; 30 31 namespace gpu { 32 namespace gles2 { 33 34 namespace { 35 36 struct UniformType { 37 explicit UniformType(const ShaderTranslator::VariableInfo uniform) 38 : type(uniform.type), 39 size(uniform.size), 40 precision(uniform.precision) { } 41 42 UniformType() 43 : type(0), 44 size(0), 45 precision(SH_PRECISION_MEDIUMP) { } 46 47 bool operator==(const UniformType& other) const { 48 return type == other.type && 49 size == other.size && 50 precision == other.precision; 51 } 52 53 int type; 54 int size; 55 int precision; 56 }; 57 58 int ShaderTypeToIndex(GLenum shader_type) { 59 switch (shader_type) { 60 case GL_VERTEX_SHADER: 61 return 0; 62 case GL_FRAGMENT_SHADER: 63 return 1; 64 default: 65 NOTREACHED(); 66 return 0; 67 } 68 } 69 70 // Given a name like "foo.bar[123].moo[456]" sets new_name to "foo.bar[123].moo" 71 // and sets element_index to 456. returns false if element expression was not a 72 // whole decimal number. For example: "foo[1b2]" 73 bool GetUniformNameSansElement( 74 const std::string& name, int* element_index, std::string* new_name) { 75 DCHECK(element_index); 76 DCHECK(new_name); 77 if (name.size() < 3 || name[name.size() - 1] != ']') { 78 *element_index = 0; 79 *new_name = name; 80 return true; 81 } 82 83 // Look for an array specification. 84 size_t open_pos = name.find_last_of('['); 85 if (open_pos == std::string::npos || 86 open_pos >= name.size() - 2) { 87 return false; 88 } 89 90 GLint index = 0; 91 size_t last = name.size() - 1; 92 for (size_t pos = open_pos + 1; pos < last; ++pos) { 93 int8 digit = name[pos] - '0'; 94 if (digit < 0 || digit > 9) { 95 return false; 96 } 97 index = index * 10 + digit; 98 } 99 100 *element_index = index; 101 *new_name = name.substr(0, open_pos); 102 return true; 103 } 104 105 bool IsBuiltInVarying(const std::string& name) { 106 // Built-in variables. 107 const char* kBuiltInVaryings[] = { 108 "gl_FragCoord", 109 "gl_FrontFacing", 110 "gl_PointCoord" 111 }; 112 for (size_t ii = 0; ii < arraysize(kBuiltInVaryings); ++ii) { 113 if (name == kBuiltInVaryings[ii]) 114 return true; 115 } 116 return false; 117 } 118 119 } // anonymous namespace. 120 121 Program::UniformInfo::UniformInfo() 122 : size(0), 123 type(GL_NONE), 124 fake_location_base(0), 125 is_array(false) { 126 } 127 128 Program::UniformInfo::UniformInfo( 129 GLsizei _size, 130 GLenum _type, 131 int _fake_location_base, 132 const std::string& _name) 133 : size(_size), 134 type(_type), 135 fake_location_base(_fake_location_base), 136 is_array(false), 137 name(_name) { 138 } 139 140 Program::UniformInfo::~UniformInfo() {} 141 142 bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) { 143 static const char kInvalidPrefix[] = { 'g', 'l', '_' }; 144 return (length >= sizeof(kInvalidPrefix) && 145 memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0); 146 } 147 148 Program::Program( 149 ProgramManager* manager, GLuint service_id) 150 : manager_(manager), 151 use_count_(0), 152 max_attrib_name_length_(0), 153 max_uniform_name_length_(0), 154 service_id_(service_id), 155 deleted_(false), 156 valid_(false), 157 link_status_(false), 158 uniforms_cleared_(false), 159 num_uniforms_(0) { 160 manager_->StartTracking(this); 161 } 162 163 void Program::Reset() { 164 valid_ = false; 165 link_status_ = false; 166 num_uniforms_ = 0; 167 max_uniform_name_length_ = 0; 168 max_attrib_name_length_ = 0; 169 attrib_infos_.clear(); 170 uniform_infos_.clear(); 171 sampler_indices_.clear(); 172 attrib_location_to_index_map_.clear(); 173 } 174 175 std::string Program::ProcessLogInfo( 176 const std::string& log) { 177 std::string output; 178 re2::StringPiece input(log); 179 std::string prior_log; 180 std::string hashed_name; 181 while (RE2::Consume(&input, 182 "(.*)(webgl_[0123456789abcdefABCDEF]+)", 183 &prior_log, 184 &hashed_name)) { 185 output += prior_log; 186 187 const std::string* original_name = 188 GetOriginalNameFromHashedName(hashed_name); 189 if (original_name) 190 output += *original_name; 191 else 192 output += hashed_name; 193 } 194 195 return output + input.as_string(); 196 } 197 198 void Program::UpdateLogInfo() { 199 GLint max_len = 0; 200 glGetProgramiv(service_id_, GL_INFO_LOG_LENGTH, &max_len); 201 if (max_len == 0) { 202 set_log_info(NULL); 203 return; 204 } 205 scoped_ptr<char[]> temp(new char[max_len]); 206 GLint len = 0; 207 glGetProgramInfoLog(service_id_, max_len, &len, temp.get()); 208 DCHECK(max_len == 0 || len < max_len); 209 DCHECK(len == 0 || temp[len] == '\0'); 210 std::string log(temp.get(), len); 211 set_log_info(ProcessLogInfo(log).c_str()); 212 } 213 214 void Program::ClearUniforms( 215 std::vector<uint8>* zero_buffer) { 216 DCHECK(zero_buffer); 217 if (uniforms_cleared_) { 218 return; 219 } 220 uniforms_cleared_ = true; 221 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) { 222 const UniformInfo& uniform_info = uniform_infos_[ii]; 223 if (!uniform_info.IsValid()) { 224 continue; 225 } 226 GLint location = uniform_info.element_locations[0]; 227 GLsizei size = uniform_info.size; 228 uint32 unit_size = GLES2Util::GetGLDataTypeSizeForUniforms( 229 uniform_info.type); 230 uint32 size_needed = size * unit_size; 231 if (size_needed > zero_buffer->size()) { 232 zero_buffer->resize(size_needed, 0u); 233 } 234 const void* zero = &(*zero_buffer)[0]; 235 switch (uniform_info.type) { 236 case GL_FLOAT: 237 glUniform1fv(location, size, reinterpret_cast<const GLfloat*>(zero)); 238 break; 239 case GL_FLOAT_VEC2: 240 glUniform2fv(location, size, reinterpret_cast<const GLfloat*>(zero)); 241 break; 242 case GL_FLOAT_VEC3: 243 glUniform3fv(location, size, reinterpret_cast<const GLfloat*>(zero)); 244 break; 245 case GL_FLOAT_VEC4: 246 glUniform4fv(location, size, reinterpret_cast<const GLfloat*>(zero)); 247 break; 248 case GL_INT: 249 case GL_BOOL: 250 case GL_SAMPLER_2D: 251 case GL_SAMPLER_CUBE: 252 case GL_SAMPLER_EXTERNAL_OES: 253 case GL_SAMPLER_3D_OES: 254 case GL_SAMPLER_2D_RECT_ARB: 255 glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero)); 256 break; 257 case GL_INT_VEC2: 258 case GL_BOOL_VEC2: 259 glUniform2iv(location, size, reinterpret_cast<const GLint*>(zero)); 260 break; 261 case GL_INT_VEC3: 262 case GL_BOOL_VEC3: 263 glUniform3iv(location, size, reinterpret_cast<const GLint*>(zero)); 264 break; 265 case GL_INT_VEC4: 266 case GL_BOOL_VEC4: 267 glUniform4iv(location, size, reinterpret_cast<const GLint*>(zero)); 268 break; 269 case GL_FLOAT_MAT2: 270 glUniformMatrix2fv( 271 location, size, false, reinterpret_cast<const GLfloat*>(zero)); 272 break; 273 case GL_FLOAT_MAT3: 274 glUniformMatrix3fv( 275 location, size, false, reinterpret_cast<const GLfloat*>(zero)); 276 break; 277 case GL_FLOAT_MAT4: 278 glUniformMatrix4fv( 279 location, size, false, reinterpret_cast<const GLfloat*>(zero)); 280 break; 281 default: 282 NOTREACHED(); 283 break; 284 } 285 } 286 } 287 288 namespace { 289 290 struct UniformData { 291 UniformData() : size(-1), type(GL_NONE), location(0), added(false) { 292 } 293 std::string queried_name; 294 std::string corrected_name; 295 std::string original_name; 296 GLsizei size; 297 GLenum type; 298 GLint location; 299 bool added; 300 }; 301 302 struct UniformDataComparer { 303 bool operator()(const UniformData& lhs, const UniformData& rhs) const { 304 return lhs.queried_name < rhs.queried_name; 305 } 306 }; 307 308 } // anonymous namespace 309 310 void Program::Update() { 311 Reset(); 312 UpdateLogInfo(); 313 link_status_ = true; 314 uniforms_cleared_ = false; 315 GLint num_attribs = 0; 316 GLint max_len = 0; 317 GLint max_location = -1; 318 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs); 319 glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len); 320 // TODO(gman): Should we check for error? 321 scoped_ptr<char[]> name_buffer(new char[max_len]); 322 for (GLint ii = 0; ii < num_attribs; ++ii) { 323 GLsizei length = 0; 324 GLsizei size = 0; 325 GLenum type = 0; 326 glGetActiveAttrib( 327 service_id_, ii, max_len, &length, &size, &type, name_buffer.get()); 328 DCHECK(max_len == 0 || length < max_len); 329 DCHECK(length == 0 || name_buffer[length] == '\0'); 330 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) { 331 std::string name; 332 std::string original_name; 333 GetCorrectedVariableInfo( 334 false, name_buffer.get(), &name, &original_name, &size, &type); 335 // TODO(gman): Should we check for error? 336 GLint location = glGetAttribLocation(service_id_, name_buffer.get()); 337 if (location > max_location) { 338 max_location = location; 339 } 340 attrib_infos_.push_back( 341 VertexAttrib(size, type, original_name, location)); 342 max_attrib_name_length_ = std::max( 343 max_attrib_name_length_, static_cast<GLsizei>(original_name.size())); 344 } 345 } 346 347 // Create attrib location to index map. 348 attrib_location_to_index_map_.resize(max_location + 1); 349 for (GLint ii = 0; ii <= max_location; ++ii) { 350 attrib_location_to_index_map_[ii] = -1; 351 } 352 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) { 353 const VertexAttrib& info = attrib_infos_[ii]; 354 attrib_location_to_index_map_[info.location] = ii; 355 } 356 357 #if !defined(NDEBUG) 358 if (CommandLine::ForCurrentProcess()->HasSwitch( 359 switches::kEnableGPUServiceLoggingGPU)) { 360 DLOG(INFO) << "----: attribs for service_id: " << service_id(); 361 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) { 362 const VertexAttrib& info = attrib_infos_[ii]; 363 DLOG(INFO) << ii << ": loc = " << info.location 364 << ", size = " << info.size 365 << ", type = " << GLES2Util::GetStringEnum(info.type) 366 << ", name = " << info.name; 367 } 368 } 369 #endif 370 371 max_len = 0; 372 GLint num_uniforms = 0; 373 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms); 374 glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len); 375 name_buffer.reset(new char[max_len]); 376 377 // Reads all the names. 378 std::vector<UniformData> uniform_data; 379 for (GLint ii = 0; ii < num_uniforms; ++ii) { 380 GLsizei length = 0; 381 UniformData data; 382 glGetActiveUniform( 383 service_id_, ii, max_len, &length, 384 &data.size, &data.type, name_buffer.get()); 385 DCHECK(max_len == 0 || length < max_len); 386 DCHECK(length == 0 || name_buffer[length] == '\0'); 387 if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) { 388 data.queried_name = std::string(name_buffer.get()); 389 GetCorrectedVariableInfo( 390 true, name_buffer.get(), &data.corrected_name, &data.original_name, 391 &data.size, &data.type); 392 uniform_data.push_back(data); 393 } 394 } 395 396 // NOTE: We don't care if 2 uniforms are bound to the same location. 397 // One of them will take preference. The spec allows this, same as 398 // BindAttribLocation. 399 // 400 // The reason we don't check is if we were to fail we'd have to 401 // restore the previous program but since we've already linked successfully 402 // at this point the previous program is gone. 403 404 // Assigns the uniforms with bindings. 405 size_t next_available_index = 0; 406 for (size_t ii = 0; ii < uniform_data.size(); ++ii) { 407 UniformData& data = uniform_data[ii]; 408 data.location = glGetUniformLocation( 409 service_id_, data.queried_name.c_str()); 410 // remove "[0]" 411 std::string short_name; 412 int element_index = 0; 413 bool good ALLOW_UNUSED = GetUniformNameSansElement( 414 data.queried_name, &element_index, &short_name);\ 415 DCHECK(good); 416 LocationMap::const_iterator it = bind_uniform_location_map_.find( 417 short_name); 418 if (it != bind_uniform_location_map_.end()) { 419 data.added = AddUniformInfo( 420 data.size, data.type, data.location, it->second, data.corrected_name, 421 data.original_name, &next_available_index); 422 } 423 } 424 425 // Assigns the uniforms that were not bound. 426 for (size_t ii = 0; ii < uniform_data.size(); ++ii) { 427 const UniformData& data = uniform_data[ii]; 428 if (!data.added) { 429 AddUniformInfo( 430 data.size, data.type, data.location, -1, data.corrected_name, 431 data.original_name, &next_available_index); 432 } 433 } 434 435 #if !defined(NDEBUG) 436 if (CommandLine::ForCurrentProcess()->HasSwitch( 437 switches::kEnableGPUServiceLoggingGPU)) { 438 DLOG(INFO) << "----: uniforms for service_id: " << service_id(); 439 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) { 440 const UniformInfo& info = uniform_infos_[ii]; 441 if (info.IsValid()) { 442 DLOG(INFO) << ii << ": loc = " << info.element_locations[0] 443 << ", size = " << info.size 444 << ", type = " << GLES2Util::GetStringEnum(info.type) 445 << ", name = " << info.name; 446 } 447 } 448 } 449 #endif 450 451 valid_ = true; 452 } 453 454 void Program::ExecuteBindAttribLocationCalls() { 455 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin(); 456 it != bind_attrib_location_map_.end(); ++it) { 457 const std::string* mapped_name = GetAttribMappedName(it->first); 458 if (mapped_name && *mapped_name != it->first) 459 glBindAttribLocation(service_id_, it->second, mapped_name->c_str()); 460 } 461 } 462 463 void ProgramManager::DoCompileShader( 464 Shader* shader, 465 ShaderTranslator* translator, 466 ProgramManager::TranslatedShaderSourceType translated_shader_source_type) { 467 // Translate GL ES 2.0 shader to Desktop GL shader and pass that to 468 // glShaderSource and then glCompileShader. 469 const std::string* source = shader->source(); 470 const char* shader_src = source ? source->c_str() : ""; 471 if (translator) { 472 if (!translator->Translate(shader_src)) { 473 shader->SetStatus(false, translator->info_log(), NULL); 474 return; 475 } 476 shader_src = translator->translated_shader(); 477 if (translated_shader_source_type != kANGLE) 478 shader->UpdateTranslatedSource(shader_src); 479 } 480 481 glShaderSource(shader->service_id(), 1, &shader_src, NULL); 482 glCompileShader(shader->service_id()); 483 if (translated_shader_source_type == kANGLE) { 484 GLint max_len = 0; 485 glGetShaderiv(shader->service_id(), 486 GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE, 487 &max_len); 488 scoped_ptr<char[]> temp(new char[max_len]); 489 GLint len = 0; 490 glGetTranslatedShaderSourceANGLE( 491 shader->service_id(), max_len, &len, temp.get()); 492 DCHECK(max_len == 0 || len < max_len); 493 DCHECK(len == 0 || temp[len] == '\0'); 494 shader->UpdateTranslatedSource(max_len ? temp.get() : NULL); 495 } 496 497 GLint status = GL_FALSE; 498 glGetShaderiv(shader->service_id(), GL_COMPILE_STATUS, &status); 499 if (status) { 500 shader->SetStatus(true, "", translator); 501 } else { 502 // We cannot reach here if we are using the shader translator. 503 // All invalid shaders must be rejected by the translator. 504 // All translated shaders must compile. 505 GLint max_len = 0; 506 glGetShaderiv(shader->service_id(), GL_INFO_LOG_LENGTH, &max_len); 507 scoped_ptr<char[]> temp(new char[max_len]); 508 GLint len = 0; 509 glGetShaderInfoLog(shader->service_id(), max_len, &len, temp.get()); 510 DCHECK(max_len == 0 || len < max_len); 511 DCHECK(len == 0 || temp[len] == '\0'); 512 shader->SetStatus(false, std::string(temp.get(), len).c_str(), NULL); 513 LOG_IF(ERROR, translator) 514 << "Shader translator allowed/produced an invalid shader " 515 << "unless the driver is buggy:" 516 << "\n--original-shader--\n" << (source ? *source : std::string()) 517 << "\n--translated-shader--\n" << shader_src << "\n--info-log--\n" 518 << *shader->log_info(); 519 } 520 } 521 522 bool Program::Link(ShaderManager* manager, 523 ShaderTranslator* vertex_translator, 524 ShaderTranslator* fragment_translator, 525 Program::VaryingsPackingOption varyings_packing_option, 526 const ShaderCacheCallback& shader_callback) { 527 ClearLinkStatus(); 528 if (!CanLink()) { 529 set_log_info("missing shaders"); 530 return false; 531 } 532 if (DetectAttribLocationBindingConflicts()) { 533 set_log_info("glBindAttribLocation() conflicts"); 534 return false; 535 } 536 if (DetectUniformsMismatch()) { 537 set_log_info("Uniforms with the same name but different type/precision"); 538 return false; 539 } 540 if (DetectVaryingsMismatch()) { 541 set_log_info("Varyings with the same name but different type, " 542 "or statically used varyings in fragment shader are not " 543 "declared in vertex shader"); 544 return false; 545 } 546 if (DetectGlobalNameConflicts()) { 547 set_log_info("Name conflicts between an uniform and an attribute"); 548 return false; 549 } 550 if (!CheckVaryingsPacking(varyings_packing_option)) { 551 set_log_info("Varyings over maximum register limit"); 552 return false; 553 } 554 555 TimeTicks before_time = TimeTicks::HighResNow(); 556 bool link = true; 557 ProgramCache* cache = manager_->program_cache_; 558 if (cache) { 559 DCHECK(attached_shaders_[0]->signature_source() && 560 attached_shaders_[1]->signature_source()); 561 ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus( 562 *attached_shaders_[0]->signature_source(), 563 vertex_translator, 564 *attached_shaders_[1]->signature_source(), 565 fragment_translator, 566 &bind_attrib_location_map_); 567 568 if (status == ProgramCache::LINK_SUCCEEDED) { 569 ProgramCache::ProgramLoadResult success = 570 cache->LoadLinkedProgram(service_id(), 571 attached_shaders_[0].get(), 572 vertex_translator, 573 attached_shaders_[1].get(), 574 fragment_translator, 575 &bind_attrib_location_map_, 576 shader_callback); 577 link = success != ProgramCache::PROGRAM_LOAD_SUCCESS; 578 UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link); 579 } 580 } 581 582 if (link) { 583 ExecuteBindAttribLocationCalls(); 584 before_time = TimeTicks::HighResNow(); 585 if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) { 586 glProgramParameteri(service_id(), 587 PROGRAM_BINARY_RETRIEVABLE_HINT, 588 GL_TRUE); 589 } 590 glLinkProgram(service_id()); 591 } 592 593 GLint success = 0; 594 glGetProgramiv(service_id(), GL_LINK_STATUS, &success); 595 if (success == GL_TRUE) { 596 Update(); 597 if (link) { 598 if (cache) { 599 cache->SaveLinkedProgram(service_id(), 600 attached_shaders_[0].get(), 601 vertex_translator, 602 attached_shaders_[1].get(), 603 fragment_translator, 604 &bind_attrib_location_map_, 605 shader_callback); 606 } 607 UMA_HISTOGRAM_CUSTOM_COUNTS( 608 "GPU.ProgramCache.BinaryCacheMissTime", 609 (TimeTicks::HighResNow() - before_time).InMicroseconds(), 610 0, 611 TimeDelta::FromSeconds(10).InMicroseconds(), 612 50); 613 } else { 614 UMA_HISTOGRAM_CUSTOM_COUNTS( 615 "GPU.ProgramCache.BinaryCacheHitTime", 616 (TimeTicks::HighResNow() - before_time).InMicroseconds(), 617 0, 618 TimeDelta::FromSeconds(1).InMicroseconds(), 619 50); 620 } 621 } else { 622 UpdateLogInfo(); 623 } 624 return success == GL_TRUE; 625 } 626 627 void Program::Validate() { 628 if (!IsValid()) { 629 set_log_info("program not linked"); 630 return; 631 } 632 glValidateProgram(service_id()); 633 UpdateLogInfo(); 634 } 635 636 GLint Program::GetUniformFakeLocation( 637 const std::string& name) const { 638 bool getting_array_location = false; 639 size_t open_pos = std::string::npos; 640 int index = 0; 641 if (!GLES2Util::ParseUniformName( 642 name, &open_pos, &index, &getting_array_location)) { 643 return -1; 644 } 645 for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) { 646 const UniformInfo& info = uniform_infos_[ii]; 647 if (!info.IsValid()) { 648 continue; 649 } 650 if (info.name == name || 651 (info.is_array && 652 info.name.compare(0, info.name.size() - 3, name) == 0)) { 653 return info.fake_location_base; 654 } else if (getting_array_location && info.is_array) { 655 // Look for an array specification. 656 size_t open_pos_2 = info.name.find_last_of('['); 657 if (open_pos_2 == open_pos && 658 name.compare(0, open_pos, info.name, 0, open_pos) == 0) { 659 if (index >= 0 && index < info.size) { 660 DCHECK_GT(static_cast<int>(info.element_locations.size()), index); 661 if (info.element_locations[index] == -1) 662 return -1; 663 return ProgramManager::MakeFakeLocation( 664 info.fake_location_base, index); 665 } 666 } 667 } 668 } 669 return -1; 670 } 671 672 GLint Program::GetAttribLocation( 673 const std::string& name) const { 674 for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) { 675 const VertexAttrib& info = attrib_infos_[ii]; 676 if (info.name == name) { 677 return info.location; 678 } 679 } 680 return -1; 681 } 682 683 const Program::UniformInfo* 684 Program::GetUniformInfoByFakeLocation( 685 GLint fake_location, GLint* real_location, GLint* array_index) const { 686 DCHECK(real_location); 687 DCHECK(array_index); 688 if (fake_location < 0) { 689 return NULL; 690 } 691 692 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location); 693 if (uniform_index >= 0 && 694 static_cast<size_t>(uniform_index) < uniform_infos_.size()) { 695 const UniformInfo& uniform_info = uniform_infos_[uniform_index]; 696 if (!uniform_info.IsValid()) { 697 return NULL; 698 } 699 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location); 700 if (element_index < uniform_info.size) { 701 *real_location = uniform_info.element_locations[element_index]; 702 *array_index = element_index; 703 return &uniform_info; 704 } 705 } 706 return NULL; 707 } 708 709 const std::string* Program::GetAttribMappedName( 710 const std::string& original_name) const { 711 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { 712 Shader* shader = attached_shaders_[ii].get(); 713 if (shader) { 714 const std::string* mapped_name = 715 shader->GetAttribMappedName(original_name); 716 if (mapped_name) 717 return mapped_name; 718 } 719 } 720 return NULL; 721 } 722 723 const std::string* Program::GetOriginalNameFromHashedName( 724 const std::string& hashed_name) const { 725 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { 726 Shader* shader = attached_shaders_[ii].get(); 727 if (shader) { 728 const std::string* original_name = 729 shader->GetOriginalNameFromHashedName(hashed_name); 730 if (original_name) 731 return original_name; 732 } 733 } 734 return NULL; 735 } 736 737 bool Program::SetUniformLocationBinding( 738 const std::string& name, GLint location) { 739 std::string short_name; 740 int element_index = 0; 741 if (!GetUniformNameSansElement(name, &element_index, &short_name) || 742 element_index != 0) { 743 return false; 744 } 745 746 bind_uniform_location_map_[short_name] = location; 747 return true; 748 } 749 750 // Note: This is only valid to call right after a program has been linked 751 // successfully. 752 void Program::GetCorrectedVariableInfo( 753 bool use_uniforms, 754 const std::string& name, std::string* corrected_name, 755 std::string* original_name, 756 GLsizei* size, GLenum* type) const { 757 DCHECK(corrected_name); 758 DCHECK(original_name); 759 DCHECK(size); 760 DCHECK(type); 761 const char* kArraySpec = "[0]"; 762 for (int jj = 0; jj < 2; ++jj) { 763 std::string test_name(name + ((jj == 1) ? kArraySpec : "")); 764 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { 765 Shader* shader = attached_shaders_[ii].get(); 766 if (shader) { 767 const Shader::VariableInfo* variable_info = 768 use_uniforms ? shader->GetUniformInfo(test_name) : 769 shader->GetAttribInfo(test_name); 770 // Note: There is an assuption here that if an attrib is defined in more 771 // than 1 attached shader their types and sizes match. Should we check 772 // for that case? 773 if (variable_info) { 774 *corrected_name = test_name; 775 *original_name = variable_info->name; 776 *type = variable_info->type; 777 *size = variable_info->size; 778 return; 779 } 780 } 781 } 782 } 783 *corrected_name = name; 784 *original_name = name; 785 } 786 787 bool Program::AddUniformInfo( 788 GLsizei size, GLenum type, GLint location, GLint fake_base_location, 789 const std::string& name, const std::string& original_name, 790 size_t* next_available_index) { 791 DCHECK(next_available_index); 792 const char* kArraySpec = "[0]"; 793 size_t uniform_index = 794 fake_base_location >= 0 ? fake_base_location : *next_available_index; 795 if (uniform_infos_.size() < uniform_index + 1) { 796 uniform_infos_.resize(uniform_index + 1); 797 } 798 799 // return if this location is already in use. 800 if (uniform_infos_[uniform_index].IsValid()) { 801 DCHECK_GE(fake_base_location, 0); 802 return false; 803 } 804 805 uniform_infos_[uniform_index] = UniformInfo( 806 size, type, uniform_index, original_name); 807 ++num_uniforms_; 808 809 UniformInfo& info = uniform_infos_[uniform_index]; 810 info.element_locations.resize(size); 811 info.element_locations[0] = location; 812 DCHECK_GE(size, 0); 813 size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u; 814 info.texture_units.clear(); 815 info.texture_units.resize(num_texture_units, 0); 816 817 if (size > 1) { 818 // Go through the array element locations looking for a match. 819 // We can skip the first element because it's the same as the 820 // the location without the array operators. 821 size_t array_pos = name.rfind(kArraySpec); 822 std::string base_name = name; 823 if (name.size() > 3) { 824 if (array_pos != name.size() - 3) { 825 info.name = name + kArraySpec; 826 } else { 827 base_name = name.substr(0, name.size() - 3); 828 } 829 } 830 for (GLsizei ii = 1; ii < info.size; ++ii) { 831 std::string element_name(base_name + "[" + base::IntToString(ii) + "]"); 832 info.element_locations[ii] = 833 glGetUniformLocation(service_id_, element_name.c_str()); 834 } 835 } 836 837 info.is_array = 838 (size > 1 || 839 (info.name.size() > 3 && 840 info.name.rfind(kArraySpec) == info.name.size() - 3)); 841 842 if (info.IsSampler()) { 843 sampler_indices_.push_back(info.fake_location_base); 844 } 845 max_uniform_name_length_ = 846 std::max(max_uniform_name_length_, 847 static_cast<GLsizei>(info.name.size())); 848 849 while (*next_available_index < uniform_infos_.size() && 850 uniform_infos_[*next_available_index].IsValid()) { 851 *next_available_index = *next_available_index + 1; 852 } 853 854 return true; 855 } 856 857 const Program::UniformInfo* 858 Program::GetUniformInfo( 859 GLint index) const { 860 if (static_cast<size_t>(index) >= uniform_infos_.size()) { 861 return NULL; 862 } 863 864 const UniformInfo& info = uniform_infos_[index]; 865 return info.IsValid() ? &info : NULL; 866 } 867 868 bool Program::SetSamplers( 869 GLint num_texture_units, GLint fake_location, 870 GLsizei count, const GLint* value) { 871 if (fake_location < 0) { 872 return true; 873 } 874 GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location); 875 if (uniform_index >= 0 && 876 static_cast<size_t>(uniform_index) < uniform_infos_.size()) { 877 UniformInfo& info = uniform_infos_[uniform_index]; 878 if (!info.IsValid()) { 879 return false; 880 } 881 GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location); 882 if (element_index < info.size) { 883 count = std::min(info.size - element_index, count); 884 if (info.IsSampler() && count > 0) { 885 for (GLsizei ii = 0; ii < count; ++ii) { 886 if (value[ii] < 0 || value[ii] >= num_texture_units) { 887 return false; 888 } 889 } 890 std::copy(value, value + count, 891 info.texture_units.begin() + element_index); 892 return true; 893 } 894 } 895 } 896 return true; 897 } 898 899 void Program::GetProgramiv(GLenum pname, GLint* params) { 900 switch (pname) { 901 case GL_ACTIVE_ATTRIBUTES: 902 *params = attrib_infos_.size(); 903 break; 904 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: 905 // Notice +1 to accomodate NULL terminator. 906 *params = max_attrib_name_length_ + 1; 907 break; 908 case GL_ACTIVE_UNIFORMS: 909 *params = num_uniforms_; 910 break; 911 case GL_ACTIVE_UNIFORM_MAX_LENGTH: 912 // Notice +1 to accomodate NULL terminator. 913 *params = max_uniform_name_length_ + 1; 914 break; 915 case GL_LINK_STATUS: 916 *params = link_status_; 917 break; 918 case GL_INFO_LOG_LENGTH: 919 // Notice +1 to accomodate NULL terminator. 920 *params = log_info_.get() ? (log_info_->size() + 1) : 0; 921 break; 922 case GL_DELETE_STATUS: 923 *params = deleted_; 924 break; 925 case GL_VALIDATE_STATUS: 926 if (!IsValid()) { 927 *params = GL_FALSE; 928 } else { 929 glGetProgramiv(service_id_, pname, params); 930 } 931 break; 932 default: 933 glGetProgramiv(service_id_, pname, params); 934 break; 935 } 936 } 937 938 bool Program::AttachShader( 939 ShaderManager* shader_manager, 940 Shader* shader) { 941 DCHECK(shader_manager); 942 DCHECK(shader); 943 int index = ShaderTypeToIndex(shader->shader_type()); 944 if (attached_shaders_[index].get() != NULL) { 945 return false; 946 } 947 attached_shaders_[index] = scoped_refptr<Shader>(shader); 948 shader_manager->UseShader(shader); 949 return true; 950 } 951 952 bool Program::DetachShader( 953 ShaderManager* shader_manager, 954 Shader* shader) { 955 DCHECK(shader_manager); 956 DCHECK(shader); 957 if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() != 958 shader) { 959 return false; 960 } 961 attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL; 962 shader_manager->UnuseShader(shader); 963 return true; 964 } 965 966 void Program::DetachShaders(ShaderManager* shader_manager) { 967 DCHECK(shader_manager); 968 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { 969 if (attached_shaders_[ii].get()) { 970 DetachShader(shader_manager, attached_shaders_[ii].get()); 971 } 972 } 973 } 974 975 bool Program::CanLink() const { 976 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { 977 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid()) { 978 return false; 979 } 980 } 981 return true; 982 } 983 984 bool Program::DetectAttribLocationBindingConflicts() const { 985 std::set<GLint> location_binding_used; 986 for (LocationMap::const_iterator it = bind_attrib_location_map_.begin(); 987 it != bind_attrib_location_map_.end(); ++it) { 988 // Find out if an attribute is declared in this program's shaders. 989 bool active = false; 990 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { 991 if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid()) 992 continue; 993 if (attached_shaders_[ii]->GetAttribInfo(it->first)) { 994 active = true; 995 break; 996 } 997 } 998 if (active) { 999 std::pair<std::set<GLint>::iterator, bool> result = 1000 location_binding_used.insert(it->second); 1001 if (!result.second) 1002 return true; 1003 } 1004 } 1005 return false; 1006 } 1007 1008 bool Program::DetectUniformsMismatch() const { 1009 typedef std::map<std::string, UniformType> UniformMap; 1010 UniformMap uniform_map; 1011 for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { 1012 const ShaderTranslator::VariableMap& shader_uniforms = 1013 attached_shaders_[ii]->uniform_map(); 1014 for (ShaderTranslator::VariableMap::const_iterator iter = 1015 shader_uniforms.begin(); 1016 iter != shader_uniforms.end(); ++iter) { 1017 const std::string& name = iter->first; 1018 UniformType type(iter->second); 1019 UniformMap::iterator map_entry = uniform_map.find(name); 1020 if (map_entry == uniform_map.end()) { 1021 uniform_map[name] = type; 1022 } else { 1023 // If a uniform is already in the map, i.e., it has already been 1024 // declared by other shader, then the type and precision must match. 1025 if (map_entry->second == type) 1026 continue; 1027 return true; 1028 } 1029 } 1030 } 1031 return false; 1032 } 1033 1034 bool Program::DetectVaryingsMismatch() const { 1035 DCHECK(attached_shaders_[0] && 1036 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER && 1037 attached_shaders_[1] && 1038 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER); 1039 const ShaderTranslator::VariableMap* vertex_varyings = 1040 &(attached_shaders_[0]->varying_map()); 1041 const ShaderTranslator::VariableMap* fragment_varyings = 1042 &(attached_shaders_[1]->varying_map()); 1043 1044 for (ShaderTranslator::VariableMap::const_iterator iter = 1045 fragment_varyings->begin(); 1046 iter != fragment_varyings->end(); ++iter) { 1047 const std::string& name = iter->first; 1048 if (IsBuiltInVarying(name)) 1049 continue; 1050 1051 ShaderTranslator::VariableMap::const_iterator hit = 1052 vertex_varyings->find(name); 1053 if (hit == vertex_varyings->end()) { 1054 if (iter->second.static_use) 1055 return true; 1056 continue; 1057 } 1058 1059 if (hit->second.type != iter->second.type || 1060 hit->second.size != iter->second.size) 1061 return true; 1062 1063 } 1064 return false; 1065 } 1066 1067 bool Program::DetectGlobalNameConflicts() const { 1068 DCHECK(attached_shaders_[0] && 1069 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER && 1070 attached_shaders_[1] && 1071 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER); 1072 const ShaderTranslator::VariableMap* uniforms[2]; 1073 uniforms[0] = &(attached_shaders_[0]->uniform_map()); 1074 uniforms[1] = &(attached_shaders_[1]->uniform_map()); 1075 const ShaderTranslator::VariableMap* attribs = 1076 &(attached_shaders_[0]->attrib_map()); 1077 1078 for (ShaderTranslator::VariableMap::const_iterator iter = 1079 attribs->begin(); iter != attribs->end(); ++iter) { 1080 for (int ii = 0; ii < 2; ++ii) { 1081 if (uniforms[ii]->find(iter->first) != uniforms[ii]->end()) 1082 return true; 1083 } 1084 } 1085 return false; 1086 } 1087 1088 bool Program::CheckVaryingsPacking( 1089 Program::VaryingsPackingOption option) const { 1090 DCHECK(attached_shaders_[0] && 1091 attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER && 1092 attached_shaders_[1] && 1093 attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER); 1094 const ShaderTranslator::VariableMap* vertex_varyings = 1095 &(attached_shaders_[0]->varying_map()); 1096 const ShaderTranslator::VariableMap* fragment_varyings = 1097 &(attached_shaders_[1]->varying_map()); 1098 1099 std::map<std::string, ShVariableInfo> combined_map; 1100 1101 for (ShaderTranslator::VariableMap::const_iterator iter = 1102 fragment_varyings->begin(); 1103 iter != fragment_varyings->end(); ++iter) { 1104 if (!iter->second.static_use && option == kCountOnlyStaticallyUsed) 1105 continue; 1106 if (!IsBuiltInVarying(iter->first)) { 1107 ShaderTranslator::VariableMap::const_iterator vertex_iter = 1108 vertex_varyings->find(iter->first); 1109 if (vertex_iter == vertex_varyings->end() || 1110 (!vertex_iter->second.static_use && 1111 option == kCountOnlyStaticallyUsed)) 1112 continue; 1113 } 1114 1115 ShVariableInfo var; 1116 var.type = static_cast<ShDataType>(iter->second.type); 1117 var.size = iter->second.size; 1118 combined_map[iter->first] = var; 1119 } 1120 1121 if (combined_map.size() == 0) 1122 return true; 1123 scoped_ptr<ShVariableInfo[]> variables( 1124 new ShVariableInfo[combined_map.size()]); 1125 size_t index = 0; 1126 for (std::map<std::string, ShVariableInfo>::const_iterator iter = 1127 combined_map.begin(); 1128 iter != combined_map.end(); ++iter) { 1129 variables[index].type = iter->second.type; 1130 variables[index].size = iter->second.size; 1131 ++index; 1132 } 1133 return ShCheckVariablesWithinPackingLimits( 1134 static_cast<int>(manager_->max_varying_vectors()), 1135 variables.get(), 1136 combined_map.size()) == 1; 1137 } 1138 1139 static uint32 ComputeOffset(const void* start, const void* position) { 1140 return static_cast<const uint8*>(position) - 1141 static_cast<const uint8*>(start); 1142 } 1143 1144 void Program::GetProgramInfo( 1145 ProgramManager* manager, CommonDecoder::Bucket* bucket) const { 1146 // NOTE: It seems to me the math in here does not need check for overflow 1147 // because the data being calucated from has various small limits. The max 1148 // number of attribs + uniforms is somewhere well under 1024. The maximum size 1149 // of an identifier is 256 characters. 1150 uint32 num_locations = 0; 1151 uint32 total_string_size = 0; 1152 1153 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) { 1154 const VertexAttrib& info = attrib_infos_[ii]; 1155 num_locations += 1; 1156 total_string_size += info.name.size(); 1157 } 1158 1159 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) { 1160 const UniformInfo& info = uniform_infos_[ii]; 1161 if (info.IsValid()) { 1162 num_locations += info.element_locations.size(); 1163 total_string_size += info.name.size(); 1164 } 1165 } 1166 1167 uint32 num_inputs = attrib_infos_.size() + num_uniforms_; 1168 uint32 input_size = num_inputs * sizeof(ProgramInput); 1169 uint32 location_size = num_locations * sizeof(int32); 1170 uint32 size = sizeof(ProgramInfoHeader) + 1171 input_size + location_size + total_string_size; 1172 1173 bucket->SetSize(size); 1174 ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size); 1175 ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>( 1176 sizeof(ProgramInfoHeader), input_size); 1177 int32* locations = bucket->GetDataAs<int32*>( 1178 sizeof(ProgramInfoHeader) + input_size, location_size); 1179 char* strings = bucket->GetDataAs<char*>( 1180 sizeof(ProgramInfoHeader) + input_size + location_size, 1181 total_string_size); 1182 DCHECK(header); 1183 DCHECK(inputs); 1184 DCHECK(locations); 1185 DCHECK(strings); 1186 1187 header->link_status = link_status_; 1188 header->num_attribs = attrib_infos_.size(); 1189 header->num_uniforms = num_uniforms_; 1190 1191 for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) { 1192 const VertexAttrib& info = attrib_infos_[ii]; 1193 inputs->size = info.size; 1194 inputs->type = info.type; 1195 inputs->location_offset = ComputeOffset(header, locations); 1196 inputs->name_offset = ComputeOffset(header, strings); 1197 inputs->name_length = info.name.size(); 1198 *locations++ = info.location; 1199 memcpy(strings, info.name.c_str(), info.name.size()); 1200 strings += info.name.size(); 1201 ++inputs; 1202 } 1203 1204 for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) { 1205 const UniformInfo& info = uniform_infos_[ii]; 1206 if (info.IsValid()) { 1207 inputs->size = info.size; 1208 inputs->type = info.type; 1209 inputs->location_offset = ComputeOffset(header, locations); 1210 inputs->name_offset = ComputeOffset(header, strings); 1211 inputs->name_length = info.name.size(); 1212 DCHECK(static_cast<size_t>(info.size) == info.element_locations.size()); 1213 for (size_t jj = 0; jj < info.element_locations.size(); ++jj) { 1214 if (info.element_locations[jj] == -1) 1215 *locations++ = -1; 1216 else 1217 *locations++ = ProgramManager::MakeFakeLocation(ii, jj); 1218 } 1219 memcpy(strings, info.name.c_str(), info.name.size()); 1220 strings += info.name.size(); 1221 ++inputs; 1222 } 1223 } 1224 1225 DCHECK_EQ(ComputeOffset(header, strings), size); 1226 } 1227 1228 Program::~Program() { 1229 if (manager_) { 1230 if (manager_->have_context_) { 1231 glDeleteProgram(service_id()); 1232 } 1233 manager_->StopTracking(this); 1234 manager_ = NULL; 1235 } 1236 } 1237 1238 1239 ProgramManager::ProgramManager(ProgramCache* program_cache, 1240 uint32 max_varying_vectors) 1241 : program_count_(0), 1242 have_context_(true), 1243 program_cache_(program_cache), 1244 max_varying_vectors_(max_varying_vectors) { } 1245 1246 ProgramManager::~ProgramManager() { 1247 DCHECK(programs_.empty()); 1248 } 1249 1250 void ProgramManager::Destroy(bool have_context) { 1251 have_context_ = have_context; 1252 programs_.clear(); 1253 } 1254 1255 void ProgramManager::StartTracking(Program* /* program */) { 1256 ++program_count_; 1257 } 1258 1259 void ProgramManager::StopTracking(Program* /* program */) { 1260 --program_count_; 1261 } 1262 1263 Program* ProgramManager::CreateProgram( 1264 GLuint client_id, GLuint service_id) { 1265 std::pair<ProgramMap::iterator, bool> result = 1266 programs_.insert( 1267 std::make_pair(client_id, 1268 scoped_refptr<Program>( 1269 new Program(this, service_id)))); 1270 DCHECK(result.second); 1271 return result.first->second.get(); 1272 } 1273 1274 Program* ProgramManager::GetProgram(GLuint client_id) { 1275 ProgramMap::iterator it = programs_.find(client_id); 1276 return it != programs_.end() ? it->second.get() : NULL; 1277 } 1278 1279 bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const { 1280 // This doesn't need to be fast. It's only used during slow queries. 1281 for (ProgramMap::const_iterator it = programs_.begin(); 1282 it != programs_.end(); ++it) { 1283 if (it->second->service_id() == service_id) { 1284 *client_id = it->first; 1285 return true; 1286 } 1287 } 1288 return false; 1289 } 1290 1291 ProgramCache* ProgramManager::program_cache() const { 1292 return program_cache_; 1293 } 1294 1295 bool ProgramManager::IsOwned(Program* program) { 1296 for (ProgramMap::iterator it = programs_.begin(); 1297 it != programs_.end(); ++it) { 1298 if (it->second.get() == program) { 1299 return true; 1300 } 1301 } 1302 return false; 1303 } 1304 1305 void ProgramManager::RemoveProgramInfoIfUnused( 1306 ShaderManager* shader_manager, Program* program) { 1307 DCHECK(shader_manager); 1308 DCHECK(program); 1309 DCHECK(IsOwned(program)); 1310 if (program->IsDeleted() && !program->InUse()) { 1311 program->DetachShaders(shader_manager); 1312 for (ProgramMap::iterator it = programs_.begin(); 1313 it != programs_.end(); ++it) { 1314 if (it->second.get() == program) { 1315 programs_.erase(it); 1316 return; 1317 } 1318 } 1319 NOTREACHED(); 1320 } 1321 } 1322 1323 void ProgramManager::MarkAsDeleted( 1324 ShaderManager* shader_manager, 1325 Program* program) { 1326 DCHECK(shader_manager); 1327 DCHECK(program); 1328 DCHECK(IsOwned(program)); 1329 program->MarkAsDeleted(); 1330 RemoveProgramInfoIfUnused(shader_manager, program); 1331 } 1332 1333 void ProgramManager::UseProgram(Program* program) { 1334 DCHECK(program); 1335 DCHECK(IsOwned(program)); 1336 program->IncUseCount(); 1337 } 1338 1339 void ProgramManager::UnuseProgram( 1340 ShaderManager* shader_manager, 1341 Program* program) { 1342 DCHECK(shader_manager); 1343 DCHECK(program); 1344 DCHECK(IsOwned(program)); 1345 program->DecUseCount(); 1346 RemoveProgramInfoIfUnused(shader_manager, program); 1347 } 1348 1349 void ProgramManager::ClearUniforms(Program* program) { 1350 DCHECK(program); 1351 program->ClearUniforms(&zero_); 1352 } 1353 1354 int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) { 1355 return index + element * 0x10000; 1356 } 1357 1358 } // namespace gles2 1359 } // namespace gpu 1360