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 <stdlib.h> 19 #include <string.h> 20 21 ShaderParser::ShaderParser():ObjectData(SHADER_DATA), 22 m_type(0), 23 m_originalSrc(NULL), 24 m_parsedLines(NULL) { 25 m_infoLog = new GLchar[1]; 26 m_infoLog[0] = '\0'; 27 }; 28 29 ShaderParser::ShaderParser(GLenum type):ObjectData(SHADER_DATA), 30 m_type(type), 31 m_originalSrc(NULL), 32 m_parsedLines(NULL) { 33 34 m_infoLog = new GLchar[1]; 35 m_infoLog[0] = '\0'; 36 }; 37 38 void ShaderParser::setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length){ 39 for(int i = 0;i<count;i++){ 40 m_src.append(strings[i]); 41 } 42 //store original source 43 if (m_originalSrc) 44 free(m_originalSrc); 45 m_originalSrc = strdup(m_src.c_str()); 46 47 clearParsedSrc(); 48 49 // parseGLSLversion must be called first since #version should be the 50 // first token in the shader source. 51 parseGLSLversion(); 52 parseBuiltinConstants(); 53 /* 54 version 1.30.10 is the first version of GLSL Language containing precision qualifiers 55 if the glsl version is less than 1.30.10 than we will use a shader parser which omits 56 all precision qualifiers from the shader source , otherwise we will use a shader parser 57 which set the default precisions to be the same as the default precisions of GLSL ES 58 */ 59 #if 0 60 if(ver < Version(1,30,10)){ 61 parseOmitPrecision(); 62 } else { 63 parseExtendDefaultPrecision(); 64 } 65 #else 66 //XXX: Until proved otherwise, glsl doesn't know/use those precision macros, so we omit then 67 parseOmitPrecision(); 68 #endif 69 parseLineNumbers(); 70 parseOriginalSrc(); 71 } 72 const GLchar** ShaderParser::parsedLines() { 73 m_parsedLines = (GLchar*)m_parsedSrc.c_str(); 74 return const_cast<const GLchar**> (&m_parsedLines); 75 }; 76 77 const char* ShaderParser::getOriginalSrc(){ 78 return m_originalSrc; 79 } 80 81 void ShaderParser::parseLineNumbers() 82 { 83 m_parsedSrc += "#line 1\n"; 84 } 85 86 void ShaderParser::parseOriginalSrc() { 87 m_parsedSrc+=m_src; 88 } 89 90 void ShaderParser::parseGLSLversion() { 91 92 // 93 // find in shader the #version token if exist. 94 // That token should be the first non-comment or blank token 95 // 96 const char *src = m_src.c_str(); 97 const int minGLSLVersion = 120; 98 int glslVersion = minGLSLVersion; 99 enum { 100 PARSE_NONE, 101 PARSE_IN_C_COMMENT, 102 PARSE_IN_LINE_COMMENT 103 } parseState = PARSE_NONE; 104 const char *c = src; 105 106 while( c && *c != '\0') { 107 if (parseState == PARSE_IN_C_COMMENT) { 108 if (*c == '*' && *(c+1) == '/') { 109 parseState = PARSE_NONE; 110 c += 2; 111 } 112 else c++; 113 } 114 else if (parseState == PARSE_IN_LINE_COMMENT) { 115 if (*c == '\n') { 116 parseState = PARSE_NONE; 117 } 118 c++; 119 } 120 else if (*c == '/' && *(c+1) == '/') { 121 parseState = PARSE_IN_LINE_COMMENT; 122 c += 2; 123 } 124 else if (*c == '/' && *(c+1) == '*') { 125 parseState = PARSE_IN_C_COMMENT; 126 c += 2; 127 } 128 else if (*c == ' ' || *c == '\t' || *c == '\r' || *c == '\n') { 129 c++; 130 } 131 else { 132 // 133 // We have reached the first non-blank character outside 134 // a comment, this must be a #version token or else #version 135 // token does not exist in this shader source. 136 // 137 if (!strncmp(c,"#version",8)) { 138 int ver; 139 if (sscanf(c+8,"%d",&ver) == 1) { 140 // 141 // parsed version string correctly, blank out the 142 // version token from the source, we will add it later at 143 // the begining of the shader. 144 // 145 char *cc = (char *)c; 146 for (int i=0; i<8; i++,cc++) *cc = ' '; 147 while (*cc < '0' || *cc > '9') { *cc = ' '; cc++; } 148 while (*cc >= '0' && *cc <= '9') { *cc = ' '; cc++; } 149 150 // Use the version from the source but only if 151 // it is larger than our minGLSLVersion 152 if (ver > minGLSLVersion) glslVersion = ver; 153 } 154 } 155 156 // 157 // break the loop, no need to go further on the source. 158 break; 159 } 160 } 161 162 // 163 // allow to force GLSL version through environment variable 164 // 165 const char *forceVersion = getenv("GOOGLE_GLES_FORCE_GLSL_VERSION"); 166 if (forceVersion) { 167 int ver; 168 if (sscanf(forceVersion,"%d",&ver) == 1) { 169 glslVersion = ver; 170 } 171 } 172 173 // 174 // if glslVersion is defined, add it to the parsed source 175 // 176 if (glslVersion > 0) { 177 char vstr[16]; 178 sprintf(vstr,"%d",glslVersion); 179 m_parsedSrc += std::string("#version ") + 180 std::string(vstr) + 181 std::string("\n"); 182 } 183 } 184 185 void ShaderParser::parseBuiltinConstants() 186 { 187 m_parsedSrc += 188 "const int _translator_gl_MaxVertexUniformVectors = 256;\n" 189 "const int _translator_gl_MaxFragmentUniformVectors = 256;\n" 190 "const int _translator_gl_MaxVaryingVectors = 15;\n" 191 "#define gl_MaxVertexUniformVectors _translator_gl_MaxVertexUniformVectors\n" 192 "#define gl_MaxFragmentUniformVectors _translator_gl_MaxFragmentUniformVectors\n" 193 "#define gl_MaxVaryingVectors _translator_gl_MaxVaryingVectors\n"; 194 195 } 196 197 void ShaderParser::parseOmitPrecision(){ 198 199 //defines we need to add in order to Omit precisions qualifiers 200 static const GLchar defines[] = { 201 "#define GLES 1\n" 202 "#define lowp \n" 203 "#define mediump \n" 204 "#define highp \n" 205 }; 206 m_parsedSrc+=defines; 207 208 // 209 // parse the source and blank out precision statements 210 // which has the following syntax: 211 // precision {qualifier} {type}; 212 // where {qualifier} is one of lowp,mediump or hightp 213 // type is any valid GLES defined type (we do not check that here!) 214 // NOTE: This is needed in order to workaround driver bug in 215 // Intel/Linux where the compiler does not get statement like 216 // "float;", otherwise we could just define a macro named 217 // precision to be empty. 218 // 219 const char *src = m_src.c_str(); 220 221 enum { 222 PRECISION, 223 QUALIFIER, 224 SEMICOLON 225 } statementState = PRECISION; 226 const char *precision = 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