Home | History | Annotate | Download | only in libGLESv2
      1 //
      2 // Copyright (c) 2002-2010 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 // Shader.cpp: Implements the gl::Shader class and its  derived classes
      8 // VertexShader and FragmentShader. Implements GL shader objects and related
      9 // functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
     10 
     11 #include "libGLESv2/Shader.h"
     12 
     13 #include <string>
     14 
     15 #include "GLSLANG/Shaderlang.h"
     16 #include "libGLESv2/main.h"
     17 #include "libGLESv2/utilities.h"
     18 
     19 namespace gl
     20 {
     21 void *Shader::mFragmentCompiler = NULL;
     22 void *Shader::mVertexCompiler = NULL;
     23 
     24 Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
     25 {
     26     mSource = NULL;
     27     mHlsl = NULL;
     28     mInfoLog = NULL;
     29 
     30     // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
     31     if (!mFragmentCompiler)
     32     {
     33         int result = ShInitialize();
     34 
     35         if (result)
     36         {
     37             ShBuiltInResources resources;
     38             ShInitBuiltInResources(&resources);
     39             Context *context = getContext();
     40 
     41             resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
     42             resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
     43             resources.MaxVaryingVectors = context->getMaximumVaryingVectors();
     44             resources.MaxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS;
     45             resources.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
     46             resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
     47             resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors();
     48             resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
     49             resources.OES_standard_derivatives = 1;
     50 
     51             mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources);
     52             mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources);
     53         }
     54     }
     55 
     56     mRefCount = 0;
     57     mDeleteStatus = false;
     58 }
     59 
     60 Shader::~Shader()
     61 {
     62     delete[] mSource;
     63     delete[] mHlsl;
     64     delete[] mInfoLog;
     65 }
     66 
     67 GLuint Shader::getHandle() const
     68 {
     69     return mHandle;
     70 }
     71 
     72 void Shader::setSource(GLsizei count, const char **string, const GLint *length)
     73 {
     74     delete[] mSource;
     75     int totalLength = 0;
     76 
     77     for (int i = 0; i < count; i++)
     78     {
     79         if (length && length[i] >= 0)
     80         {
     81             totalLength += length[i];
     82         }
     83         else
     84         {
     85             totalLength += (int)strlen(string[i]);
     86         }
     87     }
     88 
     89     mSource = new char[totalLength + 1];
     90     char *code = mSource;
     91 
     92     for (int i = 0; i < count; i++)
     93     {
     94         int stringLength;
     95 
     96         if (length && length[i] >= 0)
     97         {
     98             stringLength = length[i];
     99         }
    100         else
    101         {
    102             stringLength = (int)strlen(string[i]);
    103         }
    104 
    105         strncpy(code, string[i], stringLength);
    106         code += stringLength;
    107     }
    108 
    109     mSource[totalLength] = '\0';
    110 }
    111 
    112 int Shader::getInfoLogLength() const
    113 {
    114     if (!mInfoLog)
    115     {
    116         return 0;
    117     }
    118     else
    119     {
    120        return strlen(mInfoLog) + 1;
    121     }
    122 }
    123 
    124 void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
    125 {
    126     int index = 0;
    127 
    128     if (mInfoLog)
    129     {
    130         while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
    131         {
    132             infoLog[index] = mInfoLog[index];
    133             index++;
    134         }
    135     }
    136 
    137     if (bufSize)
    138     {
    139         infoLog[index] = '\0';
    140     }
    141 
    142     if (length)
    143     {
    144         *length = index;
    145     }
    146 }
    147 
    148 int Shader::getSourceLength() const
    149 {
    150     if (!mSource)
    151     {
    152         return 0;
    153     }
    154     else
    155     {
    156        return strlen(mSource) + 1;
    157     }
    158 }
    159 
    160 void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
    161 {
    162     int index = 0;
    163 
    164     if (mSource)
    165     {
    166         while (index < bufSize - 1 && index < (int)strlen(mSource))
    167         {
    168             source[index] = mSource[index];
    169             index++;
    170         }
    171     }
    172 
    173     if (bufSize)
    174     {
    175         source[index] = '\0';
    176     }
    177 
    178     if (length)
    179     {
    180         *length = index;
    181     }
    182 }
    183 
    184 bool Shader::isCompiled()
    185 {
    186     return mHlsl != NULL;
    187 }
    188 
    189 const char *Shader::getHLSL()
    190 {
    191     return mHlsl;
    192 }
    193 
    194 void Shader::addRef()
    195 {
    196     mRefCount++;
    197 }
    198 
    199 void Shader::release()
    200 {
    201     mRefCount--;
    202 
    203     if (mRefCount == 0 && mDeleteStatus)
    204     {
    205         mResourceManager->deleteShader(mHandle);
    206     }
    207 }
    208 
    209 unsigned int Shader::getRefCount() const
    210 {
    211     return mRefCount;
    212 }
    213 
    214 bool Shader::isFlaggedForDeletion() const
    215 {
    216     return mDeleteStatus;
    217 }
    218 
    219 void Shader::flagForDeletion()
    220 {
    221     mDeleteStatus = true;
    222 }
    223 
    224 void Shader::releaseCompiler()
    225 {
    226     ShDestruct(mFragmentCompiler);
    227     ShDestruct(mVertexCompiler);
    228 
    229     mFragmentCompiler = NULL;
    230     mVertexCompiler = NULL;
    231 
    232     ShFinalize();
    233 }
    234 
    235 void Shader::parseVaryings()
    236 {
    237     if (mHlsl)
    238     {
    239         const char *input = strstr(mHlsl, "// Varyings") + 12;
    240 
    241         while(true)
    242         {
    243             char varyingType[256];
    244             char varyingName[256];
    245 
    246             int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
    247 
    248             if (matches != 2)
    249             {
    250                 break;
    251             }
    252 
    253             char *array = strstr(varyingName, "[");
    254             int size = 1;
    255 
    256             if (array)
    257             {
    258                 size = atoi(array + 1);
    259                 *array = '\0';
    260             }
    261 
    262             varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
    263 
    264             input = strstr(input, ";") + 2;
    265         }
    266 
    267         mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
    268         mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
    269         mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
    270         mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
    271     }
    272 }
    273 
    274 void Shader::compileToHLSL(void *compiler)
    275 {
    276     if (isCompiled() || !mSource)
    277     {
    278         return;
    279     }
    280 
    281     TRACE("\n%s", mSource);
    282 
    283     delete[] mInfoLog;
    284     mInfoLog = NULL;
    285 
    286     int result = ShCompile(compiler, &mSource, 1, SH_OBJECT_CODE);
    287 
    288     if (result)
    289     {
    290         int objCodeLen = 0;
    291         ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
    292         mHlsl = new char[objCodeLen];
    293         ShGetObjectCode(compiler, mHlsl);
    294 
    295         TRACE("\n%s", mHlsl);
    296     }
    297     else
    298     {
    299         int infoLogLen = 0;
    300         ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
    301         mInfoLog = new char[infoLogLen];
    302         ShGetInfoLog(compiler, mInfoLog);
    303 
    304         TRACE("\n%s", mInfoLog);
    305     }
    306 }
    307 
    308 GLenum Shader::parseType(const std::string &type)
    309 {
    310     if (type == "float")
    311     {
    312         return GL_FLOAT;
    313     }
    314     else if (type == "float2")
    315     {
    316         return GL_FLOAT_VEC2;
    317     }
    318     else if (type == "float3")
    319     {
    320         return GL_FLOAT_VEC3;
    321     }
    322     else if (type == "float4")
    323     {
    324         return GL_FLOAT_VEC4;
    325     }
    326     else if (type == "float2x2")
    327     {
    328         return GL_FLOAT_MAT2;
    329     }
    330     else if (type == "float3x3")
    331     {
    332         return GL_FLOAT_MAT3;
    333     }
    334     else if (type == "float4x4")
    335     {
    336         return GL_FLOAT_MAT4;
    337     }
    338     else UNREACHABLE();
    339 
    340     return GL_NONE;
    341 }
    342 
    343 // true if varying x has a higher priority in packing than y
    344 bool Shader::compareVarying(const Varying &x, const Varying &y)
    345 {
    346     if(x.type == y.type)
    347     {
    348         return x.size > y.size;
    349     }
    350 
    351     switch (x.type)
    352     {
    353       case GL_FLOAT_MAT4: return true;
    354       case GL_FLOAT_MAT2:
    355         switch(y.type)
    356         {
    357           case GL_FLOAT_MAT4: return false;
    358           case GL_FLOAT_MAT2: return true;
    359           case GL_FLOAT_VEC4: return true;
    360           case GL_FLOAT_MAT3: return true;
    361           case GL_FLOAT_VEC3: return true;
    362           case GL_FLOAT_VEC2: return true;
    363           case GL_FLOAT:      return true;
    364           default: UNREACHABLE();
    365         }
    366         break;
    367       case GL_FLOAT_VEC4:
    368         switch(y.type)
    369         {
    370           case GL_FLOAT_MAT4: return false;
    371           case GL_FLOAT_MAT2: return false;
    372           case GL_FLOAT_VEC4: return true;
    373           case GL_FLOAT_MAT3: return true;
    374           case GL_FLOAT_VEC3: return true;
    375           case GL_FLOAT_VEC2: return true;
    376           case GL_FLOAT:      return true;
    377           default: UNREACHABLE();
    378         }
    379         break;
    380       case GL_FLOAT_MAT3:
    381         switch(y.type)
    382         {
    383           case GL_FLOAT_MAT4: return false;
    384           case GL_FLOAT_MAT2: return false;
    385           case GL_FLOAT_VEC4: return false;
    386           case GL_FLOAT_MAT3: return true;
    387           case GL_FLOAT_VEC3: return true;
    388           case GL_FLOAT_VEC2: return true;
    389           case GL_FLOAT:      return true;
    390           default: UNREACHABLE();
    391         }
    392         break;
    393       case GL_FLOAT_VEC3:
    394         switch(y.type)
    395         {
    396           case GL_FLOAT_MAT4: return false;
    397           case GL_FLOAT_MAT2: return false;
    398           case GL_FLOAT_VEC4: return false;
    399           case GL_FLOAT_MAT3: return false;
    400           case GL_FLOAT_VEC3: return true;
    401           case GL_FLOAT_VEC2: return true;
    402           case GL_FLOAT:      return true;
    403           default: UNREACHABLE();
    404         }
    405         break;
    406       case GL_FLOAT_VEC2:
    407         switch(y.type)
    408         {
    409           case GL_FLOAT_MAT4: return false;
    410           case GL_FLOAT_MAT2: return false;
    411           case GL_FLOAT_VEC4: return false;
    412           case GL_FLOAT_MAT3: return false;
    413           case GL_FLOAT_VEC3: return false;
    414           case GL_FLOAT_VEC2: return true;
    415           case GL_FLOAT:      return true;
    416           default: UNREACHABLE();
    417         }
    418         break;
    419       case GL_FLOAT: return false;
    420       default: UNREACHABLE();
    421     }
    422 
    423     return false;
    424 }
    425 
    426 VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
    427 {
    428 }
    429 
    430 VertexShader::~VertexShader()
    431 {
    432 }
    433 
    434 GLenum VertexShader::getType()
    435 {
    436     return GL_VERTEX_SHADER;
    437 }
    438 
    439 void VertexShader::compile()
    440 {
    441     compileToHLSL(mVertexCompiler);
    442     parseAttributes();
    443     parseVaryings();
    444 }
    445 
    446 int VertexShader::getSemanticIndex(const std::string &attributeName)
    447 {
    448     if (!attributeName.empty())
    449     {
    450         int semanticIndex = 0;
    451         for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
    452         {
    453             if (attribute->name == attributeName)
    454             {
    455                 return semanticIndex;
    456             }
    457 
    458             semanticIndex += VariableRowCount(attribute->type);
    459         }
    460     }
    461 
    462     return -1;
    463 }
    464 
    465 void VertexShader::parseAttributes()
    466 {
    467     if (mHlsl)
    468     {
    469         const char *input = strstr(mHlsl, "// Attributes") + 14;
    470 
    471         while(true)
    472         {
    473             char attributeType[256];
    474             char attributeName[256];
    475 
    476             int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
    477 
    478             if (matches != 2)
    479             {
    480                 break;
    481             }
    482 
    483             mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
    484 
    485             input = strstr(input, ";") + 2;
    486         }
    487     }
    488 }
    489 
    490 FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
    491 {
    492 }
    493 
    494 FragmentShader::~FragmentShader()
    495 {
    496 }
    497 
    498 GLenum FragmentShader::getType()
    499 {
    500     return GL_FRAGMENT_SHADER;
    501 }
    502 
    503 void FragmentShader::compile()
    504 {
    505     compileToHLSL(mFragmentCompiler);
    506     parseVaryings();
    507     varyings.sort(compareVarying);
    508 }
    509 }
    510