• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "ShaderParser.h"
2 #include <string.h>
3 
ShaderParser()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 
ShaderParser(GLenum type)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 
setSrc(const Version & ver,GLsizei count,const GLchar ** strings,const GLint * length)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 }
parsedLines()55 const GLchar** ShaderParser::parsedLines() {
56       m_parsedLines = (GLchar*)m_parsedSrc.c_str();
57       return const_cast<const GLchar**> (&m_parsedLines);
58 };
59 
getOriginalSrc()60 const char* ShaderParser::getOriginalSrc(){
61     return m_originalSrc;
62 }
63 
parseLineNumbers()64 void ShaderParser::parseLineNumbers()
65 {
66     m_parsedSrc += "#line 1\n";
67 }
68 
parseOriginalSrc()69 void ShaderParser::parseOriginalSrc() {
70     m_parsedSrc+=m_src;
71 }
72 
parseGLSLversion()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 
parseBuiltinConstants()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 
parseOmitPrecision()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 
parseExtendDefaultPrecision()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 
clearParsedSrc()303 void ShaderParser::clearParsedSrc(){
304     m_parsedSrc.clear();
305 }
306 
getType()307 GLenum ShaderParser::getType() {
308     return m_type;
309 }
310 
setInfoLog(GLchar * infoLog)311 void ShaderParser::setInfoLog(GLchar* infoLog)
312 {
313     delete[] m_infoLog;
314     m_infoLog = infoLog;
315 }
316 
getInfoLog()317 GLchar* ShaderParser::getInfoLog()
318 {
319     return m_infoLog;
320 }
321 
~ShaderParser()322 ShaderParser::~ShaderParser(){
323     clearParsedSrc();
324     if (m_originalSrc)
325         free(m_originalSrc);
326     delete[] m_infoLog;
327 }
328