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