Home | History | Annotate | Download | only in GLES_V2
      1 #include "ShaderParser.h"
      2 #include <string.h>
      3 
      4 ShaderParser::ShaderParser():ObjectData(SHADER_DATA),
      5                              m_type(0),
      6                              m_originalSrc(NULL),
      7                              m_parsedLines(NULL) {
      8     m_infoLog = new GLchar[1];
      9     m_infoLog[0] = '\0';
     10 };
     11 
     12 ShaderParser::ShaderParser(GLenum type):ObjectData(SHADER_DATA),
     13                                         m_type(type),
     14                                         m_originalSrc(NULL),
     15                                         m_parsedLines(NULL) {
     16 
     17     m_infoLog = new GLchar[1];
     18     m_infoLog[0] = '\0';
     19 };
     20 
     21 void ShaderParser::setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length){
     22     for(int i = 0;i<count;i++){
     23         m_src.append(strings[i]);
     24     }
     25     //store original source
     26     if (m_originalSrc)
     27         free(m_originalSrc);
     28     m_originalSrc = strdup(m_src.c_str());
     29 
     30     clearParsedSrc();
     31 
     32     // parseGLSLversion must be called first since #version should be the
     33     // first token in the shader source.
     34     parseGLSLversion();
     35     parseBuiltinConstants();
     36     /*
     37       version 1.30.10 is the first version of GLSL Language containing precision qualifiers
     38       if the glsl version is less than 1.30.10 than we will use a shader parser which omits
     39       all precision qualifiers from the shader source , otherwise we will use a shader parser
     40       which set the default precisions to be the same as the default precisions of GLSL ES
     41     */
     42 #if 0
     43     if(ver < Version(1,30,10)){
     44         parseOmitPrecision();
     45      } else {
     46         parseExtendDefaultPrecision();
     47      }
     48 #else
     49     //XXX: Until proved otherwise, glsl doesn't know/use those precision macros, so we omit then
     50     parseOmitPrecision();
     51 #endif
     52     parseLineNumbers();
     53     parseOriginalSrc();
     54 }
     55 const GLchar** ShaderParser::parsedLines() {
     56       m_parsedLines = (GLchar*)m_parsedSrc.c_str();
     57       return const_cast<const GLchar**> (&m_parsedLines);
     58 };
     59 
     60 const char* ShaderParser::getOriginalSrc(){
     61     return m_originalSrc;
     62 }
     63 
     64 void ShaderParser::parseLineNumbers()
     65 {
     66     m_parsedSrc += "#line 1\n";
     67 }
     68 
     69 void ShaderParser::parseOriginalSrc() {
     70     m_parsedSrc+=m_src;
     71 }
     72 
     73 void ShaderParser::parseGLSLversion() {
     74 
     75     //
     76     // find in shader the #version token if exist.
     77     // That token should be the first non-comment or blank token
     78     //
     79     const char *src = m_src.c_str();
     80     const int minGLSLVersion = 120;
     81     int glslVersion = minGLSLVersion;
     82     enum {
     83         PARSE_NONE,
     84         PARSE_IN_C_COMMENT,
     85         PARSE_IN_LINE_COMMENT
     86     } parseState = PARSE_NONE;
     87     const char *c = src;
     88 
     89     while( c && *c != '\0') {
     90         if (parseState == PARSE_IN_C_COMMENT) {
     91             if (*c == '*' && *(c+1) == '/') {
     92                 parseState = PARSE_NONE;
     93                 c += 2;
     94             }
     95             else c++;
     96         }
     97         else if (parseState == PARSE_IN_LINE_COMMENT) {
     98             if (*c == '\n') {
     99                 parseState = PARSE_NONE;
    100             }
    101             c++;
    102         }
    103         else if (*c == '/' && *(c+1) == '/') {
    104             parseState = PARSE_IN_LINE_COMMENT;
    105             c += 2;
    106         }
    107         else if (*c == '/' && *(c+1) == '*') {
    108             parseState = PARSE_IN_C_COMMENT;
    109             c += 2;
    110         }
    111         else if (*c == ' ' || *c == '\t' || *c == '\r' || *c == '\n') {
    112             c++;
    113         }
    114         else {
    115             //
    116             // We have reached the first non-blank character outside
    117             // a comment, this must be a #version token or else #version
    118             // token does not exist in this shader source.
    119             //
    120             if (!strncmp(c,"#version",8)) {
    121                 int ver;
    122                 if (sscanf(c+8,"%d",&ver) == 1) {
    123                     //
    124                     // parsed version string correctly, blank out the
    125                     // version token from the source, we will add it later at
    126                     // the begining of the shader.
    127                     //
    128                     char *cc = (char *)c;
    129                     for (int i=0; i<8; i++,cc++) *cc = ' ';
    130                     while (*cc < '0' || *cc > '9') { *cc = ' '; cc++; }
    131                     while (*cc >= '0' && *cc <= '9') { *cc = ' '; cc++; }
    132 
    133                     // Use the version from the source but only if
    134                     // it is larger than our minGLSLVersion
    135                     if (ver > minGLSLVersion) glslVersion = ver;
    136                 }
    137             }
    138 
    139             //
    140             // break the loop, no need to go further on the source.
    141             break;
    142         }
    143     }
    144 
    145     //
    146     // allow to force GLSL version through environment variable
    147     //
    148     const char *forceVersion = getenv("GOOGLE_GLES_FORCE_GLSL_VERSION");
    149     if (forceVersion) {
    150         int ver;
    151         if (sscanf(forceVersion,"%d",&ver) == 1) {
    152             glslVersion = ver;
    153         }
    154     }
    155 
    156     //
    157     // if glslVersion is defined, add it to the parsed source
    158     //
    159     if (glslVersion > 0) {
    160         char vstr[16];
    161         sprintf(vstr,"%d",glslVersion);
    162         m_parsedSrc += std::string("#version ") +
    163                        std::string(vstr) +
    164                        std::string("\n");
    165     }
    166 }
    167 
    168 void ShaderParser::parseBuiltinConstants()
    169 {
    170     m_parsedSrc +=
    171                    "const int _translator_gl_MaxVertexUniformVectors = 256;\n"
    172                    "const int _translator_gl_MaxFragmentUniformVectors = 256;\n"
    173                    "const int _translator_gl_MaxVaryingVectors = 15;\n"
    174                    "#define gl_MaxVertexUniformVectors _translator_gl_MaxVertexUniformVectors\n"
    175                    "#define gl_MaxFragmentUniformVectors _translator_gl_MaxFragmentUniformVectors\n"
    176                    "#define gl_MaxVaryingVectors _translator_gl_MaxVaryingVectors\n";
    177 
    178 }
    179 
    180 void ShaderParser::parseOmitPrecision(){
    181 
    182     //defines we need to add in order to Omit precisions qualifiers
    183     static const GLchar defines[] = {
    184                                          "#define GLES 1\n"
    185                                          "#define lowp \n"
    186                                          "#define mediump \n"
    187                                          "#define highp \n"
    188                                      };
    189     m_parsedSrc+=defines;
    190 
    191     //
    192     // parse the source and blank out precision statements
    193     // which has the following syntax:
    194     //   precision {qualifier} {type};
    195     // where {qualifier} is one of lowp,mediump or hightp
    196     // type is any valid GLES defined type (we do not check that here!)
    197     // NOTE: This is needed in order to workaround driver bug in
    198     //       Intel/Linux where the compiler does not get statement like
    199     //       "float;", otherwise we could just define a macro named
    200     //       precision to be empty.
    201     //
    202     const char *src = m_src.c_str();
    203 
    204     enum {
    205         PRECISION,
    206         QUALIFIER,
    207         SEMICOLON
    208     } statementState = PRECISION;
    209     const char *precision = NULL;
    210     const char *delimiter = NULL;
    211 
    212     enum {
    213         PARSE_NONE,
    214         PARSE_IN_C_COMMENT,
    215         PARSE_IN_LINE_COMMENT
    216     } parseState = PARSE_NONE;
    217     const char *c = src;
    218     const char *t = NULL;
    219 
    220     #define IS_DELIMITER(c) ( (c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n' )
    221     #define IS_TOKEN_START(c) ( ((c) >= 'a' && (c) <='z') || ((c) >= 'A' && (c) <= 'Z') )
    222     #define IS_TOKEN_DELIMITER(c) ( IS_DELIMITER(c) || (c) == ';' )
    223 
    224     while( c && *c != '\0') {
    225         if (parseState == PARSE_IN_C_COMMENT) {
    226             if (*c == '*' && *(c+1) == '/') {
    227                 parseState = PARSE_NONE;
    228                 c += 2;
    229             }
    230             else c++;
    231         }
    232         else if (parseState == PARSE_IN_LINE_COMMENT) {
    233             if (*c == '\n') {
    234                 parseState = PARSE_NONE;
    235             }
    236             c++;
    237         }
    238         else if (*c == '/' && *(c+1) == '/') {
    239             parseState = PARSE_IN_LINE_COMMENT;
    240             c += 2;
    241         }
    242         else if (*c == '/' && *(c+1) == '*') {
    243             parseState = PARSE_IN_C_COMMENT;
    244             c += 2;
    245         }
    246         else if (t && IS_TOKEN_DELIMITER(*c)) {
    247             int tokenLen = c - t;
    248             switch (statementState) {
    249             case PRECISION:
    250                 if (tokenLen == 9 && !strncmp(t,"precision",9)) {
    251                     statementState = QUALIFIER;
    252                     precision = t;
    253                 }
    254                 break;
    255             case QUALIFIER:
    256                 if ((tokenLen == 4 && !strncmp(t,"lowp",4)) ||
    257                     (tokenLen == 7 && !strncmp(t,"mediump",7)) ||
    258                     (tokenLen == 5 && !strncmp(t,"highp",5))) {
    259                     statementState = SEMICOLON;
    260                 }
    261                 else {
    262                     statementState = PRECISION;
    263                 }
    264                 break;
    265             case SEMICOLON:
    266                 if (*c == ';') {
    267                     for (char *r = (char *)precision; r<=c ; ++r) {
    268                         *r = ' '; //blank the character
    269                     }
    270                 }
    271                 statementState = PRECISION; //search for the next precision line
    272                 break;
    273             default:
    274                 break;
    275             }
    276             c++;
    277             t = NULL;
    278         }
    279         else if (IS_DELIMITER(*c)) {
    280             c++;
    281         }
    282         else {
    283             if (!t && IS_TOKEN_START(*c)) {
    284                 t = c;
    285             }
    286             c++;
    287         }
    288     }
    289 }
    290 
    291 void ShaderParser::parseExtendDefaultPrecision(){
    292 
    293     //the precision lines which we need to add to the shader
    294     static const GLchar extend[] = {
    295                                       "#define GLES 1\n"
    296                                       "precision lowp sampler2D;\n"
    297                                       "precision lowp samplerCube;\n"
    298                                    };
    299 
    300     m_parsedSrc+=extend;
    301 }
    302 
    303 void ShaderParser::clearParsedSrc(){
    304     m_parsedSrc.clear();
    305 }
    306 
    307 GLenum ShaderParser::getType() {
    308     return m_type;
    309 }
    310 
    311 void ShaderParser::setInfoLog(GLchar* infoLog)
    312 {
    313     delete[] m_infoLog;
    314     m_infoLog = infoLog;
    315 }
    316 
    317 GLchar* ShaderParser::getInfoLog()
    318 {
    319     return m_infoLog;
    320 }
    321 
    322 ShaderParser::~ShaderParser(){
    323     clearParsedSrc();
    324     if (m_originalSrc)
    325         free(m_originalSrc);
    326     delete[] m_infoLog;
    327 }
    328