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