mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-10-09 22:01:36 +00:00
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:
1 file changed
+156
-166
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user