Home | History | Annotate | Download | only in libGLESv2
      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