Concatenate GL shader sources before attempting to separable-patch

* Since we search for #version, if it appears in a separate source
  string from the rest of the shader, we fail to find the right place to
  insert the patch blocks. If we concatenate first, it makes it easier.
This commit is contained in:
baldurk committed 2018-04-13 17:01:07 +01:00
1 parent 8f3b2d9b60
commit 6e152884ce
1 file changed
+156 -166
+156 -166
View File
@@ -238,9 +238,11 @@ GLuint MakeSeparableShaderProgram(WrappedOpenGL &gl, GLenum type, vector<string>
// this will fail if e.g. a member of gl_PerVertex is declared at global scope
// (this is probably most likely for clipdistance if it's redeclared with a size)
// these strings contain whichever source string we replaced, here to scope until
// the program has been created
string subStrings[2];
// we start by concatenating the source strings to make parsing easier.
std::string src;
for(size_t i = 0; i < sources.size(); i++)
src += sources[i];
for(int blocktype = 0; blocktype < 2; blocktype++)
{
@@ -248,32 +250,18 @@ GLuint MakeSeparableShaderProgram(WrappedOpenGL &gl, GLenum type, vector<string>
if(type == eGL_VERTEX_SHADER && blocktype == 0)
continue;
string &substituted = subStrings[blocktype];
string block = blocks[blocktype];
const char *identifier = blockIdentifiers[blocktype];
bool already = false;
for(size_t i = 0; i < sources.size(); i++)
// if we find the 'identifier' (ie. the block name),
// assume this block is already present and stop.
// only try and insert this block if the shader doesn't already have it
if(src.find(identifier) != string::npos)
{
// if we find the 'identifier' (ie. the block name),
// assume this block is already present and stop
if(sources[i].find(identifier) != string::npos)
{
already = true;
break;
}
continue;
}
// only try and insert this block if the shader doesn't already have it
if(already)
continue;
for(size_t i = 0; i < sources.size(); i++)
{
string src = strings[i];
size_t len = src.length();
// find if this source contains a #version, accounting for whitespace
@@ -302,172 +290,174 @@ GLuint MakeSeparableShaderProgram(WrappedOpenGL &gl, GLenum type, vector<string>
// no #version found
if(it == string::npos)
continue;
// it now points after the #version
// skip whitespace
while(it < len && isspacetab(src[it]))
++it;
// skip number
while(it < len && src[it] >= '0' && src[it] <= '9')
++it;
// skip whitespace
while(it < len && isspacetab(src[it]))
++it;
if(!strncmp(&src[it], "core", 4))
it += sizeof("core") - 1;
if(!strncmp(&src[it], "compatibility", 13))
it += sizeof("compatibility") - 1;
if(!strncmp(&src[it], "es", 2))
it += sizeof("es") - 1;
// how deep are we in an #if. We want to place our definition
// outside of any #ifs.
int if_depth = 0;
// now skip past comments, and any #directives
while(it < len)
{
// insert at the start
it = 0;
}
else
{
// it now points after the #version
// skip whitespace
while(it < len && iswhitespace(src[it]))
while(it < len && isspacetab(src[it]))
++it;
// skip C++ style comments
if(it + 1 < len && src[it] == '/' && src[it + 1] == '/')
// skip number
while(it < len && src[it] >= '0' && src[it] <= '9')
++it;
// skip whitespace
while(it < len && isspacetab(src[it]))
++it;
if(!strncmp(&src[it], "core", 4))
it += sizeof("core") - 1;
if(!strncmp(&src[it], "compatibility", 13))
it += sizeof("compatibility") - 1;
if(!strncmp(&src[it], "es", 2))
it += sizeof("es") - 1;
// how deep are we in an #if. We want to place our definition
// outside of any #ifs.
int if_depth = 0;
// now skip past comments, and any #directives
while(it < len)
{
// keep going until the next newline
while(it < len && !isnewline(src[it]))
++it;
// skip more things
continue;
}
// skip preprocessor directives
if(src[it] == '#')
{
// skip the '#'
it++;
// skip whitespace
while(it < len && iswhitespace(src[it]))
++it;
// if it's an if, then increase our depth
// This covers:
// #if
// #ifdef
// #ifndef
if(!strncmp(&src[it], "if", 2))
// skip C++ style comments
if(it + 1 < len && src[it] == '/' && src[it + 1] == '/')
{
if_depth++;
}
else if(!strncmp(&src[it], "endif", 5))
{
if_depth--;
}
// everything else is #extension or #else or #undef or anything
// keep going until the next newline
while(it < len && !isnewline(src[it]))
{
// if we encounter a C-style comment in the middle of a #define
// we can't consume it because then we'd miss the start of it.
// Instead we break out (although we're not technically at the
// end of the pre-processor line) and let it be consumed next.
// Note that we can discount C++-style comments because they
// want to consume to the end of the line too.
if(it + 1 < len && src[it] == '/' && src[it + 1] == '*')
break;
++it;
}
// skip more things
continue;
}
// skip C style comments
if(it + 1 < len && src[it] == '/' && src[it + 1] == '*')
{
// keep going until the we reach a */
while(it + 1 < len && (src[it] != '*' || src[it + 1] != '/'))
++it;
// skip the closing */ too
it += 2;
// skip more things
continue;
}
// see if we have a precision statement, if so skip that
const char precision[] = "precision";
if(it + sizeof(precision) < len && !strncmp(&src[it], precision, sizeof(precision) - 1))
{
// since we're speculating here (although what else could it be?) we don't modify
// it until we're sure.
size_t pit = it + sizeof(precision);
// skip whitespace
while(pit < len && isspacetab(src[pit]))
++pit;
// if we now match any of the precisions, then continue consuming until the next ;
const char lowp[] = "lowp";
const char mediump[] = "mediump";
const char highp[] = "highp";
bool precisionMatch =
(pit + sizeof(lowp) < len && !strncmp(&src[pit], lowp, sizeof(lowp) - 1) &&
isspacetab(src[pit + sizeof(lowp) - 1]));
precisionMatch |=
(pit + sizeof(mediump) < len && !strncmp(&src[pit], mediump, sizeof(mediump) - 1) &&
isspacetab(src[pit + sizeof(mediump) - 1]));
precisionMatch |=
(pit + sizeof(highp) < len && !strncmp(&src[pit], highp, sizeof(highp) - 1) &&
isspacetab(src[pit + sizeof(highp) - 1]));
if(precisionMatch)
{
it = pit;
while(it < len && src[it] != ';')
// keep going until the next newline
while(it < len && !isnewline(src[it]))
++it;
++it; // skip the ; itself
// skip more things
continue;
}
// otherwise just stop here, it's not a precision statement
// skip preprocessor directives
if(src[it] == '#')
{
// skip the '#'
it++;
// skip whitespace
while(it < len && iswhitespace(src[it]))
++it;
// if it's an if, then increase our depth
// This covers:
// #if
// #ifdef
// #ifndef
if(!strncmp(&src[it], "if", 2))
{
if_depth++;
}
else if(!strncmp(&src[it], "endif", 5))
{
if_depth--;
}
// everything else is #extension or #else or #undef or anything
// keep going until the next newline
while(it < len && !isnewline(src[it]))
{
// if we encounter a C-style comment in the middle of a #define
// we can't consume it because then we'd miss the start of it.
// Instead we break out (although we're not technically at the
// end of the pre-processor line) and let it be consumed next.
// Note that we can discount C++-style comments because they
// want to consume to the end of the line too.
if(it + 1 < len && src[it] == '/' && src[it + 1] == '*')
break;
++it;
}
// skip more things
continue;
}
// skip C style comments
if(it + 1 < len && src[it] == '/' && src[it + 1] == '*')
{
// keep going until the we reach a */
while(it + 1 < len && (src[it] != '*' || src[it + 1] != '/'))
++it;
// skip the closing */ too
it += 2;
// skip more things
continue;
}
// see if we have a precision statement, if so skip that
const char precision[] = "precision";
if(it + sizeof(precision) < len && !strncmp(&src[it], precision, sizeof(precision) - 1))
{
// since we're speculating here (although what else could it be?) we don't modify
// it until we're sure.
size_t pit = it + sizeof(precision);
// skip whitespace
while(pit < len && isspacetab(src[pit]))
++pit;
// if we now match any of the precisions, then continue consuming until the next ;
const char lowp[] = "lowp";
const char mediump[] = "mediump";
const char highp[] = "highp";
bool precisionMatch =
(pit + sizeof(lowp) < len && !strncmp(&src[pit], lowp, sizeof(lowp) - 1) &&
isspacetab(src[pit + sizeof(lowp) - 1]));
precisionMatch |= (pit + sizeof(mediump) < len &&
!strncmp(&src[pit], mediump, sizeof(mediump) - 1) &&
isspacetab(src[pit + sizeof(mediump) - 1]));
precisionMatch |=
(pit + sizeof(highp) < len && !strncmp(&src[pit], highp, sizeof(highp) - 1) &&
isspacetab(src[pit + sizeof(highp) - 1]));
if(precisionMatch)
{
it = pit;
while(it < len && src[it] != ';')
++it;
++it; // skip the ; itself
// skip more things
continue;
}
// otherwise just stop here, it's not a precision statement
}
// nothing more to skip, check if we're outside an if
if(if_depth == 0)
break;
// if not, this might not be a comment, etc etc. Just skip to the next line
// so we can keep going to find the #endif
while(it < len && !isnewline(src[it]))
++it;
}
// nothing more to skip, check if we're outside an if
if(if_depth == 0)
break;
// if not, this might not be a comment, etc etc. Just skip to the next line
// so we can keep going to find the #endif
while(it < len && !isnewline(src[it]))
++it;
}
substituted = src;
substituted.insert(it, block);
strings[i] = substituted.c_str();
break;
if(it < src.length())
src.insert(it, block);
}
}
sepProg = CreateSepProgram(gl, type, (GLsizei)sources.size(), strings, numPaths, paths);
const char *c_src = src.c_str();
sepProg = CreateSepProgram(gl, type, 1, &c_src, numPaths, paths);
}
gl.glGetProgramiv(sepProg, eGL_LINK_STATUS, &status);