From 6e152884ce2ab4da86260b13833d265bca8e862a Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 13 Apr 2018 17:01:07 +0100 Subject: [PATCH] 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. --- renderdoc/driver/gl/gl_shader_refl.cpp | 322 ++++++++++++------------- 1 file changed, 156 insertions(+), 166 deletions(-) diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index e2e6537dd..43286afb3 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -238,9 +238,11 @@ GLuint MakeSeparableShaderProgram(WrappedOpenGL &gl, GLenum type, vector // 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 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 // 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);