1 #include "precompiled.h" 2 // 3 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 // 7 8 // Program.cpp: Implements the gl::Program class. Implements GL program objects 9 // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. 10 11 #include "libGLESv2/Program.h" 12 #include "libGLESv2/ProgramBinary.h" 13 #include "libGLESv2/ResourceManager.h" 14 15 namespace gl 16 { 17 const char * const g_fakepath = "C:\\fakepath"; 18 19 AttributeBindings::AttributeBindings() 20 { 21 } 22 23 AttributeBindings::~AttributeBindings() 24 { 25 } 26 27 InfoLog::InfoLog() : mInfoLog(NULL) 28 { 29 } 30 31 InfoLog::~InfoLog() 32 { 33 delete[] mInfoLog; 34 } 35 36 37 int InfoLog::getLength() const 38 { 39 if (!mInfoLog) 40 { 41 return 0; 42 } 43 else 44 { 45 return strlen(mInfoLog) + 1; 46 } 47 } 48 49 void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog) 50 { 51 int index = 0; 52 53 if (bufSize > 0) 54 { 55 if (mInfoLog) 56 { 57 index = std::min(bufSize - 1, (int)strlen(mInfoLog)); 58 memcpy(infoLog, mInfoLog, index); 59 } 60 61 infoLog[index] = '\0'; 62 } 63 64 if (length) 65 { 66 *length = index; 67 } 68 } 69 70 // append a santized message to the program info log. 71 // The D3D compiler includes a fake file path in some of the warning or error 72 // messages, so lets remove all occurrences of this fake file path from the log. 73 void InfoLog::appendSanitized(const char *message) 74 { 75 std::string msg(message); 76 77 size_t found; 78 do 79 { 80 found = msg.find(g_fakepath); 81 if (found != std::string::npos) 82 { 83 msg.erase(found, strlen(g_fakepath)); 84 } 85 } 86 while (found != std::string::npos); 87 88 append("%s", msg.c_str()); 89 } 90 91 void InfoLog::append(const char *format, ...) 92 { 93 if (!format) 94 { 95 return; 96 } 97 98 va_list vararg; 99 va_start(vararg, format); 100 size_t infoLength = vsnprintf(NULL, 0, format, vararg); 101 va_end(vararg); 102 103 char *logPointer = NULL; 104 105 if (!mInfoLog) 106 { 107 mInfoLog = new char[infoLength + 2]; 108 logPointer = mInfoLog; 109 } 110 else 111 { 112 size_t currentlogLength = strlen(mInfoLog); 113 char *newLog = new char[currentlogLength + infoLength + 2]; 114 strcpy(newLog, mInfoLog); 115 116 delete[] mInfoLog; 117 mInfoLog = newLog; 118 119 logPointer = mInfoLog + currentlogLength; 120 } 121 122 va_start(vararg, format); 123 vsnprintf(logPointer, infoLength, format, vararg); 124 va_end(vararg); 125 126 logPointer[infoLength] = 0; 127 strcpy(logPointer + infoLength, "\n"); 128 } 129 130 void InfoLog::reset() 131 { 132 if (mInfoLog) 133 { 134 delete [] mInfoLog; 135 mInfoLog = NULL; 136 } 137 } 138 139 Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle) 140 { 141 mFragmentShader = NULL; 142 mVertexShader = NULL; 143 mProgramBinary.set(NULL); 144 mDeleteStatus = false; 145 mLinked = false; 146 mRefCount = 0; 147 mRenderer = renderer; 148 149 resetUniformBlockBindings(); 150 } 151 152 Program::~Program() 153 { 154 unlink(true); 155 156 if (mVertexShader != NULL) 157 { 158 mVertexShader->release(); 159 } 160 161 if (mFragmentShader != NULL) 162 { 163 mFragmentShader->release(); 164 } 165 } 166 167 bool Program::attachShader(Shader *shader) 168 { 169 if (shader->getType() == GL_VERTEX_SHADER) 170 { 171 if (mVertexShader) 172 { 173 return false; 174 } 175 176 mVertexShader = (VertexShader*)shader; 177 mVertexShader->addRef(); 178 } 179 else if (shader->getType() == GL_FRAGMENT_SHADER) 180 { 181 if (mFragmentShader) 182 { 183 return false; 184 } 185 186 mFragmentShader = (FragmentShader*)shader; 187 mFragmentShader->addRef(); 188 } 189 else UNREACHABLE(); 190 191 return true; 192 } 193 194 bool Program::detachShader(Shader *shader) 195 { 196 if (shader->getType() == GL_VERTEX_SHADER) 197 { 198 if (mVertexShader != shader) 199 { 200 return false; 201 } 202 203 mVertexShader->release(); 204 mVertexShader = NULL; 205 } 206 else if (shader->getType() == GL_FRAGMENT_SHADER) 207 { 208 if (mFragmentShader != shader) 209 { 210 return false; 211 } 212 213 mFragmentShader->release(); 214 mFragmentShader = NULL; 215 } 216 else UNREACHABLE(); 217 218 return true; 219 } 220 221 int Program::getAttachedShadersCount() const 222 { 223 return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0); 224 } 225 226 void AttributeBindings::bindAttributeLocation(GLuint index, const char *name) 227 { 228 if (index < MAX_VERTEX_ATTRIBS) 229 { 230 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) 231 { 232 mAttributeBinding[i].erase(name); 233 } 234 235 mAttributeBinding[index].insert(name); 236 } 237 } 238 239 void Program::bindAttributeLocation(GLuint index, const char *name) 240 { 241 mAttributeBindings.bindAttributeLocation(index, name); 242 } 243 244 // Links the HLSL code of the vertex and pixel shader by matching up their varyings, 245 // compiling them into binaries, determining the attribute mappings, and collecting 246 // a list of uniforms 247 bool Program::link() 248 { 249 unlink(false); 250 251 mInfoLog.reset(); 252 resetUniformBlockBindings(); 253 254 mProgramBinary.set(new ProgramBinary(mRenderer)); 255 mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader, 256 mTransformFeedbackVaryings, mTransformFeedbackBufferMode); 257 258 return mLinked; 259 } 260 261 int AttributeBindings::getAttributeBinding(const std::string &name) const 262 { 263 for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++) 264 { 265 if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end()) 266 { 267 return location; 268 } 269 } 270 271 return -1; 272 } 273 274 // Returns the program object to an unlinked state, before re-linking, or at destruction 275 void Program::unlink(bool destroy) 276 { 277 if (destroy) // Object being destructed 278 { 279 if (mFragmentShader) 280 { 281 mFragmentShader->release(); 282 mFragmentShader = NULL; 283 } 284 285 if (mVertexShader) 286 { 287 mVertexShader->release(); 288 mVertexShader = NULL; 289 } 290 } 291 292 mProgramBinary.set(NULL); 293 mLinked = false; 294 } 295 296 bool Program::isLinked() 297 { 298 return mLinked; 299 } 300 301 ProgramBinary* Program::getProgramBinary() const 302 { 303 return mProgramBinary.get(); 304 } 305 306 bool Program::setProgramBinary(const void *binary, GLsizei length) 307 { 308 unlink(false); 309 310 mInfoLog.reset(); 311 312 mProgramBinary.set(new ProgramBinary(mRenderer)); 313 mLinked = mProgramBinary->load(mInfoLog, binary, length); 314 if (!mLinked) 315 { 316 mProgramBinary.set(NULL); 317 } 318 319 return mLinked; 320 } 321 322 void Program::release() 323 { 324 mRefCount--; 325 326 if (mRefCount == 0 && mDeleteStatus) 327 { 328 mResourceManager->deleteProgram(mHandle); 329 } 330 } 331 332 void Program::addRef() 333 { 334 mRefCount++; 335 } 336 337 unsigned int Program::getRefCount() const 338 { 339 return mRefCount; 340 } 341 342 GLint Program::getProgramBinaryLength() const 343 { 344 ProgramBinary *programBinary = mProgramBinary.get(); 345 if (programBinary) 346 { 347 return programBinary->getLength(); 348 } 349 else 350 { 351 return 0; 352 } 353 } 354 355 int Program::getInfoLogLength() const 356 { 357 return mInfoLog.getLength(); 358 } 359 360 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) 361 { 362 return mInfoLog.getLog(bufSize, length, infoLog); 363 } 364 365 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) 366 { 367 int total = 0; 368 369 if (mVertexShader) 370 { 371 if (total < maxCount) 372 { 373 shaders[total] = mVertexShader->getHandle(); 374 } 375 376 total++; 377 } 378 379 if (mFragmentShader) 380 { 381 if (total < maxCount) 382 { 383 shaders[total] = mFragmentShader->getHandle(); 384 } 385 386 total++; 387 } 388 389 if (count) 390 { 391 *count = total; 392 } 393 } 394 395 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) 396 { 397 ProgramBinary *programBinary = getProgramBinary(); 398 if (programBinary) 399 { 400 programBinary->getActiveAttribute(index, bufsize, length, size, type, name); 401 } 402 else 403 { 404 if (bufsize > 0) 405 { 406 name[0] = '\0'; 407 } 408 409 if (length) 410 { 411 *length = 0; 412 } 413 414 *type = GL_NONE; 415 *size = 1; 416 } 417 } 418 419 GLint Program::getActiveAttributeCount() 420 { 421 ProgramBinary *programBinary = getProgramBinary(); 422 if (programBinary) 423 { 424 return programBinary->getActiveAttributeCount(); 425 } 426 else 427 { 428 return 0; 429 } 430 } 431 432 GLint Program::getActiveAttributeMaxLength() 433 { 434 ProgramBinary *programBinary = getProgramBinary(); 435 if (programBinary) 436 { 437 return programBinary->getActiveAttributeMaxLength(); 438 } 439 else 440 { 441 return 0; 442 } 443 } 444 445 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) 446 { 447 ProgramBinary *programBinary = getProgramBinary(); 448 if (programBinary) 449 { 450 return programBinary->getActiveUniform(index, bufsize, length, size, type, name); 451 } 452 else 453 { 454 if (bufsize > 0) 455 { 456 name[0] = '\0'; 457 } 458 459 if (length) 460 { 461 *length = 0; 462 } 463 464 *size = 0; 465 *type = GL_NONE; 466 } 467 } 468 469 GLint Program::getActiveUniformCount() 470 { 471 ProgramBinary *programBinary = getProgramBinary(); 472 if (programBinary) 473 { 474 return programBinary->getActiveUniformCount(); 475 } 476 else 477 { 478 return 0; 479 } 480 } 481 482 GLint Program::getActiveUniformMaxLength() 483 { 484 ProgramBinary *programBinary = getProgramBinary(); 485 if (programBinary) 486 { 487 return programBinary->getActiveUniformMaxLength(); 488 } 489 else 490 { 491 return 0; 492 } 493 } 494 495 void Program::flagForDeletion() 496 { 497 mDeleteStatus = true; 498 } 499 500 bool Program::isFlaggedForDeletion() const 501 { 502 return mDeleteStatus; 503 } 504 505 void Program::validate() 506 { 507 mInfoLog.reset(); 508 509 ProgramBinary *programBinary = getProgramBinary(); 510 if (isLinked() && programBinary) 511 { 512 programBinary->validate(mInfoLog); 513 } 514 else 515 { 516 mInfoLog.append("Program has not been successfully linked."); 517 } 518 } 519 520 bool Program::isValidated() const 521 { 522 ProgramBinary *programBinary = mProgramBinary.get(); 523 if (programBinary) 524 { 525 return programBinary->isValidated(); 526 } 527 else 528 { 529 return false; 530 } 531 } 532 533 GLint Program::getActiveUniformBlockCount() 534 { 535 ProgramBinary *programBinary = getProgramBinary(); 536 if (programBinary) 537 { 538 return static_cast<GLint>(programBinary->getActiveUniformBlockCount()); 539 } 540 else 541 { 542 return 0; 543 } 544 } 545 546 GLint Program::getActiveUniformBlockMaxLength() 547 { 548 ProgramBinary *programBinary = getProgramBinary(); 549 if (programBinary) 550 { 551 return static_cast<GLint>(programBinary->getActiveUniformBlockMaxLength()); 552 } 553 else 554 { 555 return 0; 556 } 557 } 558 559 void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding) 560 { 561 mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding; 562 } 563 564 GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const 565 { 566 return mUniformBlockBindings[uniformBlockIndex]; 567 } 568 569 void Program::resetUniformBlockBindings() 570 { 571 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++) 572 { 573 mUniformBlockBindings[blockId] = 0; 574 } 575 } 576 577 void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode) 578 { 579 mTransformFeedbackVaryings.resize(count); 580 for (GLsizei i = 0; i < count; i++) 581 { 582 mTransformFeedbackVaryings[i] = varyings[i]; 583 } 584 585 mTransformFeedbackBufferMode = bufferMode; 586 } 587 588 void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const 589 { 590 ProgramBinary *programBinary = getProgramBinary(); 591 if (programBinary && index < programBinary->getTransformFeedbackVaryingCount()) 592 { 593 const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(index); 594 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length())); 595 if (length) 596 { 597 *length = lastNameIdx; 598 } 599 if (size) 600 { 601 *size = varying.size; 602 } 603 if (type) 604 { 605 *type = varying.type; 606 } 607 if (name) 608 { 609 memcpy(name, varying.name.c_str(), lastNameIdx); 610 name[lastNameIdx] = '\0'; 611 } 612 } 613 } 614 615 GLsizei Program::getTransformFeedbackVaryingCount() const 616 { 617 ProgramBinary *programBinary = getProgramBinary(); 618 if (programBinary) 619 { 620 return static_cast<GLsizei>(programBinary->getTransformFeedbackVaryingCount()); 621 } 622 else 623 { 624 return 0; 625 } 626 } 627 628 GLsizei Program::getTransformFeedbackVaryingMaxLength() const 629 { 630 ProgramBinary *programBinary = getProgramBinary(); 631 if (programBinary) 632 { 633 GLsizei maxSize = 0; 634 for (size_t i = 0; i < programBinary->getTransformFeedbackVaryingCount(); i++) 635 { 636 const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(i); 637 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1)); 638 } 639 640 return maxSize; 641 } 642 else 643 { 644 return 0; 645 } 646 } 647 648 GLenum Program::getTransformFeedbackBufferMode() const 649 { 650 ProgramBinary *programBinary = getProgramBinary(); 651 if (programBinary) 652 { 653 return programBinary->getTransformFeedbackBufferMode(); 654 } 655 else 656 { 657 return mTransformFeedbackBufferMode; 658 } 659 } 660 661 } 662