aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp')
-rw-r--r--emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp343
1 files changed, 343 insertions, 0 deletions
diff --git a/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp b/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp
new file mode 100644
index 0000000..a80326d
--- /dev/null
+++ b/emulator/opengl/host/libs/Translator/GLES_V2/ShaderParser.cpp
@@ -0,0 +1,343 @@
+/*
+* Copyright 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "ShaderParser.h"
+#include <string.h>
+
+ShaderParser::ShaderParser():ObjectData(SHADER_DATA),
+ m_type(0),
+ m_originalSrc(NULL),
+ m_parsedLines(NULL) {
+ m_infoLog = new GLchar[1];
+ m_infoLog[0] = '\0';
+};
+
+ShaderParser::ShaderParser(GLenum type):ObjectData(SHADER_DATA),
+ m_type(type),
+ m_originalSrc(NULL),
+ m_parsedLines(NULL) {
+
+ m_infoLog = new GLchar[1];
+ m_infoLog[0] = '\0';
+};
+
+void ShaderParser::setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length){
+ for(int i = 0;i<count;i++){
+ m_src.append(strings[i]);
+ }
+ //store original source
+ if (m_originalSrc)
+ free(m_originalSrc);
+ m_originalSrc = strdup(m_src.c_str());
+
+ clearParsedSrc();
+
+ // parseGLSLversion must be called first since #version should be the
+ // first token in the shader source.
+ parseGLSLversion();
+ parseBuiltinConstants();
+ /*
+ version 1.30.10 is the first version of GLSL Language containing precision qualifiers
+ if the glsl version is less than 1.30.10 than we will use a shader parser which omits
+ all precision qualifiers from the shader source , otherwise we will use a shader parser
+ which set the default precisions to be the same as the default precisions of GLSL ES
+ */
+#if 0
+ if(ver < Version(1,30,10)){
+ parseOmitPrecision();
+ } else {
+ parseExtendDefaultPrecision();
+ }
+#else
+ //XXX: Until proved otherwise, glsl doesn't know/use those precision macros, so we omit then
+ parseOmitPrecision();
+#endif
+ parseLineNumbers();
+ parseOriginalSrc();
+}
+const GLchar** ShaderParser::parsedLines() {
+ m_parsedLines = (GLchar*)m_parsedSrc.c_str();
+ return const_cast<const GLchar**> (&m_parsedLines);
+};
+
+const char* ShaderParser::getOriginalSrc(){
+ return m_originalSrc;
+}
+
+void ShaderParser::parseLineNumbers()
+{
+ m_parsedSrc += "#line 1\n";
+}
+
+void ShaderParser::parseOriginalSrc() {
+ m_parsedSrc+=m_src;
+}
+
+void ShaderParser::parseGLSLversion() {
+
+ //
+ // find in shader the #version token if exist.
+ // That token should be the first non-comment or blank token
+ //
+ const char *src = m_src.c_str();
+ const int minGLSLVersion = 120;
+ int glslVersion = minGLSLVersion;
+ enum {
+ PARSE_NONE,
+ PARSE_IN_C_COMMENT,
+ PARSE_IN_LINE_COMMENT
+ } parseState = PARSE_NONE;
+ const char *c = src;
+
+ while( c && *c != '\0') {
+ if (parseState == PARSE_IN_C_COMMENT) {
+ if (*c == '*' && *(c+1) == '/') {
+ parseState = PARSE_NONE;
+ c += 2;
+ }
+ else c++;
+ }
+ else if (parseState == PARSE_IN_LINE_COMMENT) {
+ if (*c == '\n') {
+ parseState = PARSE_NONE;
+ }
+ c++;
+ }
+ else if (*c == '/' && *(c+1) == '/') {
+ parseState = PARSE_IN_LINE_COMMENT;
+ c += 2;
+ }
+ else if (*c == '/' && *(c+1) == '*') {
+ parseState = PARSE_IN_C_COMMENT;
+ c += 2;
+ }
+ else if (*c == ' ' || *c == '\t' || *c == '\r' || *c == '\n') {
+ c++;
+ }
+ else {
+ //
+ // We have reached the first non-blank character outside
+ // a comment, this must be a #version token or else #version
+ // token does not exist in this shader source.
+ //
+ if (!strncmp(c,"#version",8)) {
+ int ver;
+ if (sscanf(c+8,"%d",&ver) == 1) {
+ //
+ // parsed version string correctly, blank out the
+ // version token from the source, we will add it later at
+ // the begining of the shader.
+ //
+ char *cc = (char *)c;
+ for (int i=0; i<8; i++,cc++) *cc = ' ';
+ while (*cc < '0' || *cc > '9') { *cc = ' '; cc++; }
+ while (*cc >= '0' && *cc <= '9') { *cc = ' '; cc++; }
+
+ // Use the version from the source but only if
+ // it is larger than our minGLSLVersion
+ if (ver > minGLSLVersion) glslVersion = ver;
+ }
+ }
+
+ //
+ // break the loop, no need to go further on the source.
+ break;
+ }
+ }
+
+ //
+ // allow to force GLSL version through environment variable
+ //
+ const char *forceVersion = getenv("GOOGLE_GLES_FORCE_GLSL_VERSION");
+ if (forceVersion) {
+ int ver;
+ if (sscanf(forceVersion,"%d",&ver) == 1) {
+ glslVersion = ver;
+ }
+ }
+
+ //
+ // if glslVersion is defined, add it to the parsed source
+ //
+ if (glslVersion > 0) {
+ char vstr[16];
+ sprintf(vstr,"%d",glslVersion);
+ m_parsedSrc += std::string("#version ") +
+ std::string(vstr) +
+ std::string("\n");
+ }
+}
+
+void ShaderParser::parseBuiltinConstants()
+{
+ m_parsedSrc +=
+ "const int _translator_gl_MaxVertexUniformVectors = 256;\n"
+ "const int _translator_gl_MaxFragmentUniformVectors = 256;\n"
+ "const int _translator_gl_MaxVaryingVectors = 15;\n"
+ "#define gl_MaxVertexUniformVectors _translator_gl_MaxVertexUniformVectors\n"
+ "#define gl_MaxFragmentUniformVectors _translator_gl_MaxFragmentUniformVectors\n"
+ "#define gl_MaxVaryingVectors _translator_gl_MaxVaryingVectors\n";
+
+}
+
+void ShaderParser::parseOmitPrecision(){
+
+ //defines we need to add in order to Omit precisions qualifiers
+ static const GLchar defines[] = {
+ "#define GLES 1\n"
+ "#define lowp \n"
+ "#define mediump \n"
+ "#define highp \n"
+ };
+ m_parsedSrc+=defines;
+
+ //
+ // parse the source and blank out precision statements
+ // which has the following syntax:
+ // precision {qualifier} {type};
+ // where {qualifier} is one of lowp,mediump or hightp
+ // type is any valid GLES defined type (we do not check that here!)
+ // NOTE: This is needed in order to workaround driver bug in
+ // Intel/Linux where the compiler does not get statement like
+ // "float;", otherwise we could just define a macro named
+ // precision to be empty.
+ //
+ const char *src = m_src.c_str();
+
+ enum {
+ PRECISION,
+ QUALIFIER,
+ SEMICOLON
+ } statementState = PRECISION;
+ const char *precision = NULL;
+ const char *delimiter = NULL;
+
+ enum {
+ PARSE_NONE,
+ PARSE_IN_C_COMMENT,
+ PARSE_IN_LINE_COMMENT
+ } parseState = PARSE_NONE;
+ const char *c = src;
+ const char *t = NULL;
+
+ #define IS_DELIMITER(c) ( (c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n' )
+ #define IS_TOKEN_START(c) ( ((c) >= 'a' && (c) <='z') || ((c) >= 'A' && (c) <= 'Z') )
+ #define IS_TOKEN_DELIMITER(c) ( IS_DELIMITER(c) || (c) == ';' )
+
+ while( c && *c != '\0') {
+ if (parseState == PARSE_IN_C_COMMENT) {
+ if (*c == '*' && *(c+1) == '/') {
+ parseState = PARSE_NONE;
+ c += 2;
+ }
+ else c++;
+ }
+ else if (parseState == PARSE_IN_LINE_COMMENT) {
+ if (*c == '\n') {
+ parseState = PARSE_NONE;
+ }
+ c++;
+ }
+ else if (*c == '/' && *(c+1) == '/') {
+ parseState = PARSE_IN_LINE_COMMENT;
+ c += 2;
+ }
+ else if (*c == '/' && *(c+1) == '*') {
+ parseState = PARSE_IN_C_COMMENT;
+ c += 2;
+ }
+ else if (t && IS_TOKEN_DELIMITER(*c)) {
+ int tokenLen = c - t;
+ switch (statementState) {
+ case PRECISION:
+ if (tokenLen == 9 && !strncmp(t,"precision",9)) {
+ statementState = QUALIFIER;
+ precision = t;
+ }
+ break;
+ case QUALIFIER:
+ if ((tokenLen == 4 && !strncmp(t,"lowp",4)) ||
+ (tokenLen == 7 && !strncmp(t,"mediump",7)) ||
+ (tokenLen == 5 && !strncmp(t,"highp",5))) {
+ statementState = SEMICOLON;
+ }
+ else {
+ statementState = PRECISION;
+ }
+ break;
+ case SEMICOLON:
+ if (*c == ';') {
+ for (char *r = (char *)precision; r<=c ; ++r) {
+ *r = ' '; //blank the character
+ }
+ }
+ statementState = PRECISION; //search for the next precision line
+ break;
+ default:
+ break;
+ }
+ c++;
+ t = NULL;
+ }
+ else if (IS_DELIMITER(*c)) {
+ c++;
+ }
+ else {
+ if (!t && IS_TOKEN_START(*c)) {
+ t = c;
+ }
+ c++;
+ }
+ }
+}
+
+void ShaderParser::parseExtendDefaultPrecision(){
+
+ //the precision lines which we need to add to the shader
+ static const GLchar extend[] = {
+ "#define GLES 1\n"
+ "precision lowp sampler2D;\n"
+ "precision lowp samplerCube;\n"
+ };
+
+ m_parsedSrc+=extend;
+}
+
+void ShaderParser::clearParsedSrc(){
+ m_parsedSrc.clear();
+}
+
+GLenum ShaderParser::getType() {
+ return m_type;
+}
+
+void ShaderParser::setInfoLog(GLchar* infoLog)
+{
+ delete[] m_infoLog;
+ m_infoLog = infoLog;
+}
+
+GLchar* ShaderParser::getInfoLog()
+{
+ return m_infoLog;
+}
+
+ShaderParser::~ShaderParser(){
+ clearParsedSrc();
+ if (m_originalSrc)
+ free(m_originalSrc);
+ delete[] m_infoLog;
+}