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