1 // 2 // Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Program.cpp: Implements the gl::Program class. Implements GL program objects 8 // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. 9 10 #include "libGLESv2/Program.h" 11 #include "libGLESv2/ProgramBinary.h" 12 #include "libGLESv2/ResourceManager.h" 13 #include "libGLESv2/renderer/Renderer.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 = 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 = 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(const Caps &caps) 248 { 249 unlink(false); 250 251 mInfoLog.reset(); 252 resetUniformBlockBindings(); 253 254 mProgramBinary.set(new ProgramBinary(mRenderer->createProgram())); 255 mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader, 256 mTransformFeedbackVaryings, mTransformFeedbackBufferMode, caps); 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(GLenum binaryFormat, const void *binary, GLsizei length) 307 { 308 unlink(false); 309 310 mInfoLog.reset(); 311 312 mProgramBinary.set(new ProgramBinary(mRenderer->createProgram())); 313 mLinked = mProgramBinary->load(mInfoLog, binaryFormat, binary, length); 314 315 if (!mLinked) 316 { 317 mProgramBinary.set(NULL); 318 } 319 320 return mLinked; 321 } 322 323 void Program::release() 324 { 325 mRefCount--; 326 327 if (mRefCount == 0 && mDeleteStatus) 328 { 329 mResourceManager->deleteProgram(mHandle); 330 } 331 } 332 333 void Program::addRef() 334 { 335 mRefCount++; 336 } 337 338 unsigned int Program::getRefCount() const 339 { 340 return mRefCount; 341 } 342 343 GLint Program::getProgramBinaryLength() const 344 { 345 ProgramBinary *programBinary = mProgramBinary.get(); 346 if (programBinary) 347 { 348 return programBinary->getLength(); 349 } 350 else 351 { 352 return 0; 353 } 354 } 355 356 int Program::getInfoLogLength() const 357 { 358 return mInfoLog.getLength(); 359 } 360 361 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) 362 { 363 return mInfoLog.getLog(bufSize, length, infoLog); 364 } 365 366 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) 367 { 368 int total = 0; 369 370 if (mVertexShader) 371 { 372 if (total < maxCount) 373 { 374 shaders[total] = mVertexShader->getHandle(); 375 } 376 377 total++; 378 } 379 380 if (mFragmentShader) 381 { 382 if (total < maxCount) 383 { 384 shaders[total] = mFragmentShader->getHandle(); 385 } 386 387 total++; 388 } 389 390 if (count) 391 { 392 *count = total; 393 } 394 } 395 396 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) 397 { 398 ProgramBinary *programBinary = getProgramBinary(); 399 if (programBinary) 400 { 401 programBinary->getActiveAttribute(index, bufsize, length, size, type, name); 402 } 403 else 404 { 405 if (bufsize > 0) 406 { 407 name[0] = '\0'; 408 } 409 410 if (length) 411 { 412 *length = 0; 413 } 414 415 *type = GL_NONE; 416 *size = 1; 417 } 418 } 419 420 GLint Program::getActiveAttributeCount() 421 { 422 ProgramBinary *programBinary = getProgramBinary(); 423 if (programBinary) 424 { 425 return programBinary->getActiveAttributeCount(); 426 } 427 else 428 { 429 return 0; 430 } 431 } 432 433 GLint Program::getActiveAttributeMaxLength() 434 { 435 ProgramBinary *programBinary = getProgramBinary(); 436 if (programBinary) 437 { 438 return programBinary->getActiveAttributeMaxLength(); 439 } 440 else 441 { 442 return 0; 443 } 444 } 445 446 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) 447 { 448 ProgramBinary *programBinary = getProgramBinary(); 449 if (programBinary) 450 { 451 return programBinary->getActiveUniform(index, bufsize, length, size, type, name); 452 } 453 else 454 { 455 if (bufsize > 0) 456 { 457 name[0] = '\0'; 458 } 459 460 if (length) 461 { 462 *length = 0; 463 } 464 465 *size = 0; 466 *type = GL_NONE; 467 } 468 } 469 470 GLint Program::getActiveUniformCount() 471 { 472 ProgramBinary *programBinary = getProgramBinary(); 473 if (programBinary) 474 { 475 return programBinary->getActiveUniformCount(); 476 } 477 else 478 { 479 return 0; 480 } 481 } 482 483 GLint Program::getActiveUniformMaxLength() 484 { 485 ProgramBinary *programBinary = getProgramBinary(); 486 if (programBinary) 487 { 488 return programBinary->getActiveUniformMaxLength(); 489 } 490 else 491 { 492 return 0; 493 } 494 } 495 496 void Program::flagForDeletion() 497 { 498 mDeleteStatus = true; 499 } 500 501 bool Program::isFlaggedForDeletion() const 502 { 503 return mDeleteStatus; 504 } 505 506 void Program::validate(const Caps &caps) 507 { 508 mInfoLog.reset(); 509 510 ProgramBinary *programBinary = getProgramBinary(); 511 if (isLinked() && programBinary) 512 { 513 programBinary->validate(mInfoLog, caps); 514 } 515 else 516 { 517 mInfoLog.append("Program has not been successfully linked."); 518 } 519 } 520 521 bool Program::isValidated() const 522 { 523 ProgramBinary *programBinary = mProgramBinary.get(); 524 if (programBinary) 525 { 526 return programBinary->isValidated(); 527 } 528 else 529 { 530 return false; 531 } 532 } 533 534 GLint Program::getActiveUniformBlockCount() 535 { 536 ProgramBinary *programBinary = getProgramBinary(); 537 if (programBinary) 538 { 539 return static_cast<GLint>(programBinary->getActiveUniformBlockCount()); 540 } 541 else 542 { 543 return 0; 544 } 545 } 546 547 GLint Program::getActiveUniformBlockMaxLength() 548 { 549 ProgramBinary *programBinary = getProgramBinary(); 550 if (programBinary) 551 { 552 return static_cast<GLint>(programBinary->getActiveUniformBlockMaxLength()); 553 } 554 else 555 { 556 return 0; 557 } 558 } 559 560 void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding) 561 { 562 mUniformBlockBindings[uniformBlockIndex] = uniformBlockBinding; 563 } 564 565 GLuint Program::getUniformBlockBinding(GLuint uniformBlockIndex) const 566 { 567 return mUniformBlockBindings[uniformBlockIndex]; 568 } 569 570 void Program::resetUniformBlockBindings() 571 { 572 for (unsigned int blockId = 0; blockId < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; blockId++) 573 { 574 mUniformBlockBindings[blockId] = 0; 575 } 576 } 577 578 void Program::setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode) 579 { 580 mTransformFeedbackVaryings.resize(count); 581 for (GLsizei i = 0; i < count; i++) 582 { 583 mTransformFeedbackVaryings[i] = varyings[i]; 584 } 585 586 mTransformFeedbackBufferMode = bufferMode; 587 } 588 589 void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const 590 { 591 ProgramBinary *programBinary = getProgramBinary(); 592 if (programBinary && index < programBinary->getTransformFeedbackVaryingCount()) 593 { 594 const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(index); 595 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length())); 596 if (length) 597 { 598 *length = lastNameIdx; 599 } 600 if (size) 601 { 602 *size = varying.size; 603 } 604 if (type) 605 { 606 *type = varying.type; 607 } 608 if (name) 609 { 610 memcpy(name, varying.name.c_str(), lastNameIdx); 611 name[lastNameIdx] = '\0'; 612 } 613 } 614 } 615 616 GLsizei Program::getTransformFeedbackVaryingCount() const 617 { 618 ProgramBinary *programBinary = getProgramBinary(); 619 if (programBinary) 620 { 621 return static_cast<GLsizei>(programBinary->getTransformFeedbackVaryingCount()); 622 } 623 else 624 { 625 return 0; 626 } 627 } 628 629 GLsizei Program::getTransformFeedbackVaryingMaxLength() const 630 { 631 ProgramBinary *programBinary = getProgramBinary(); 632 if (programBinary) 633 { 634 GLsizei maxSize = 0; 635 for (size_t i = 0; i < programBinary->getTransformFeedbackVaryingCount(); i++) 636 { 637 const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(i); 638 maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1)); 639 } 640 641 return maxSize; 642 } 643 else 644 { 645 return 0; 646 } 647 } 648 649 GLenum Program::getTransformFeedbackBufferMode() const 650 { 651 ProgramBinary *programBinary = getProgramBinary(); 652 if (programBinary) 653 { 654 return programBinary->getTransformFeedbackBufferMode(); 655 } 656 else 657 { 658 return mTransformFeedbackBufferMode; 659 } 660 } 661 662 } 663