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