From: Mikko Rasa Date: Tue, 10 Apr 2018 15:53:00 +0000 (+0300) Subject: Use a #pragma as shader stage delimiter X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=4bee7581168e0803dd24568b61e590d2a4830f96 Use a #pragma as shader stage delimiter The special comment was a bad idea with poorly defined semantics. --- diff --git a/shaderlib/ambientocclusion.glsl b/shaderlib/ambientocclusion.glsl index 286072c0..7f1e79a0 100644 --- a/shaderlib/ambientocclusion.glsl +++ b/shaderlib/ambientocclusion.glsl @@ -14,7 +14,7 @@ uniform AmbientOcclusionParams float occlusion_radius; }; -////// fragment +#pragma MSP stage(fragment) vec3 project(vec3 position) { vec4 pp = projection_matrix*vec4(position, 1.0); diff --git a/shaderlib/ambientocclusion_combine.glsl b/shaderlib/ambientocclusion_combine.glsl index f56bddbc..1e8bd821 100644 --- a/shaderlib/ambientocclusion_combine.glsl +++ b/shaderlib/ambientocclusion_combine.glsl @@ -1,7 +1,7 @@ import postprocess; import ambientocclusion; -////// fragment +#pragma MSP stage(fragment) void main() { vec3 center = unproject(vec3(vertex.xy, texture(depth, texcoord).r)); diff --git a/shaderlib/ambientocclusion_occlude.glsl b/shaderlib/ambientocclusion_occlude.glsl index 6d04d438..2a10bde3 100644 --- a/shaderlib/ambientocclusion_occlude.glsl +++ b/shaderlib/ambientocclusion_occlude.glsl @@ -1,7 +1,7 @@ import postprocess; import ambientocclusion; -////// fragment +#pragma MSP stage(fragment) void main() { vec4 rv = texture(rotate, gl_FragCoord.xy/4.0)*2.0-1.0; diff --git a/shaderlib/bloom_blur.glsl b/shaderlib/bloom_blur.glsl index 958a5301..aadde901 100644 --- a/shaderlib/bloom_blur.glsl +++ b/shaderlib/bloom_blur.glsl @@ -1,7 +1,7 @@ import postprocess; import bloom; -////// fragment +#pragma MSP stage(fragment) void main() { frag_color = vec4(0.0, 0.0, 0.0, 0.0); diff --git a/shaderlib/bloom_combine.glsl b/shaderlib/bloom_combine.glsl index 4e46776d..40668636 100644 --- a/shaderlib/bloom_combine.glsl +++ b/shaderlib/bloom_combine.glsl @@ -1,7 +1,7 @@ import postprocess; import bloom; -////// fragment +#pragma MSP stage(fragment) void main() { frag_color = mix(texture(source, texcoord), texture(blurred, texcoord), strength); diff --git a/shaderlib/colorcurve.glsl b/shaderlib/colorcurve.glsl index 63f63138..23b5577d 100644 --- a/shaderlib/colorcurve.glsl +++ b/shaderlib/colorcurve.glsl @@ -7,7 +7,7 @@ uniform ToneMapping vec3 brightness_response; }; -////// fragment +#pragma MSP stage(fragment) void main() { vec4 incoming = texture(source, texcoord); diff --git a/shaderlib/postprocess.glsl b/shaderlib/postprocess.glsl index ff395cde..0e632037 100644 --- a/shaderlib/postprocess.glsl +++ b/shaderlib/postprocess.glsl @@ -1,6 +1,6 @@ uniform sampler2D source; -////// vertex +#pragma MSP stage(vertex) in vec4 vertex; void main() { @@ -9,5 +9,5 @@ void main() passthrough; } -////// fragment +#pragma MSP stage(fragment) out vec4 frag_color; diff --git a/shaderlib/singlepass.glsl b/shaderlib/singlepass.glsl index a80ca339..50c3841f 100644 --- a/shaderlib/singlepass.glsl +++ b/shaderlib/singlepass.glsl @@ -76,7 +76,7 @@ uniform Clipping ClipPlane clip_planes[max_clip_planes]; }; -////// vertex +#pragma MSP stage(vertex) layout(location=0) in vec4 vertex; layout(location=8) in vec4 texcoord; layout(location=3) in vec4 color; @@ -127,7 +127,7 @@ void main() passthrough; } -////// fragment +#pragma MSP stage(fragment) layout(location=0) out vec4 frag_color; vec4 get_diffuse_sample() diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp index 2dabd7cd..425941ba 100644 --- a/source/programcompiler.cpp +++ b/source/programcompiler.cpp @@ -13,12 +13,12 @@ using namespace std; namespace { const char builtins_src[] = - "////// vertex\n" + "#pragma MSP stage(vertex)\n" "out gl_PerVertex {\n" " vec4 gl_Position;\n" " float gl_ClipDistance[];\n" - "};" - "////// geometry\n" + "};\n" + "#pragma MSP stage(geometry)\n" "in gl_PerVertex {\n" " vec4 gl_Position;\n" " float gl_ClipDistance[];\n" diff --git a/source/programparser.cpp b/source/programparser.cpp index c3049dd3..e7343547 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -1,3 +1,4 @@ +#include #include #include #include "programparser.h" @@ -91,35 +92,26 @@ Module &ProgramParser::parse(IO::Base &io, const string &n) void ProgramParser::parse_source() { - delete module; - module = new Module; - cur_stage = &module->shared; - iter = source.begin(); - current_line = 1; while(1) { - while(RefPtr statement = parse_global_declaration()) - cur_stage->content.body.push_back(statement); - - parse_token(); - string token = parse_token(); - if(token.empty()) + string::size_type slashes = source.find("//////"); + if(slashes==string::npos) break; - else if(token=="vertex") - module->stages.push_back(VERTEX); - else if(token=="geometry") - module->stages.push_back(GEOMETRY); - else if(token=="fragment") - module->stages.push_back(FRAGMENT); - else - throw runtime_error(format("Parse error at '%s': expected stage identifier", token)); - - if(cur_stage->type!=SHARED) - module->stages.back().previous = cur_stage; - cur_stage = &module->stages.back(); - for(; (iter!=source.end() && *iter!='\n'); ++iter) ; + string::size_type newline = source.find('\n', slashes); + string pragma = format("#pragma MSP stage(%s)", source.substr(slashes+6, newline-slashes-6)); + source.replace(slashes, newline-slashes, pragma); } + + delete module; + module = new Module; + cur_stage = &module->shared; + iter = source.begin(); + source_end = source.end(); + current_line = 1; + allow_preprocess = true; + while(RefPtr statement = parse_global_declaration()) + cur_stage->content.body.push_back(statement); } string ProgramParser::format_error(const std::string &message) @@ -154,21 +146,30 @@ const string &ProgramParser::parse_token() string ProgramParser::parse_token_() { - if(!skip_comment_and_whitespace()) - return string(); - - if(isalpha(*iter) || *iter=='_') - return parse_identifier(); - else if(isdigit(*iter)) - return parse_number(); - else - return parse_other(); + while(1) + { + skip_comment_and_whitespace(); + if(iter==source_end) + return string(); + else if(allow_preprocess && *iter=='#') + { + allow_preprocess = false; + SetForScope > clear_tokens(next_tokens, deque()); + preprocess(); + } + else if(isalpha(*iter) || *iter=='_') + return parse_identifier(); + else if(isdigit(*iter)) + return parse_number(); + else + return parse_other(); + } } string ProgramParser::parse_identifier() { string ident; - while(iter!=source.end()) + while(iter!=source_end) { if(isalnum(*iter) || *iter=='_') ident += *iter++; @@ -183,7 +184,7 @@ string ProgramParser::parse_number() { bool accept_sign = false; string number; - while(iter!=source.end()) + while(iter!=source_end) { if(isdigit(*iter) || *iter=='.') number += *iter++; @@ -203,11 +204,11 @@ string ProgramParser::parse_number() string ProgramParser::parse_other() { - if(iter==source.end()) + if(iter==source_end) return string(); string token(1, *iter++); - for(unsigned i=1; (i<3 && iter!=source.end()); ++i) + for(unsigned i=1; (i<3 && iter!=source_end); ++i) { bool matched = false; for(const Operator *j=operators; (!matched && j->type); ++j) @@ -226,11 +227,10 @@ string ProgramParser::parse_other() return token; } -bool ProgramParser::skip_comment_and_whitespace() +void ProgramParser::skip_comment_and_whitespace() { unsigned comment = 0; - unsigned slashes = 0; - while(iter!=source.end()) + while(iter!=source_end) { if(comment==0) { @@ -242,10 +242,7 @@ bool ProgramParser::skip_comment_and_whitespace() else if(comment==1) { if(*iter=='/') - { comment = 2; - slashes = 2; - } else if(*iter=='*') comment = 3; else @@ -259,10 +256,6 @@ bool ProgramParser::skip_comment_and_whitespace() { if(*iter=='\n') comment = 0; - else if(*iter=='/') - ++slashes; - else if(!isspace(*iter) && slashes>=6) - return false; } else if(comment==3 && *iter=='*') comment = 4; @@ -275,12 +268,13 @@ bool ProgramParser::skip_comment_and_whitespace() } if(*iter=='\n') + { ++current_line; + allow_preprocess = (comment<3); + } ++iter; } - - return iter!=source.end(); } void ProgramParser::expect(const string &token) @@ -351,9 +345,82 @@ bool ProgramParser::is_identifier(const string &token) return re.match(token); } +void ProgramParser::preprocess() +{ + expect("#"); + + string::const_iterator line_end = iter; + for(; (line_end!=source_end && *line_end!='\n'); ++line_end) ; + SetForScope stop_at_line_end(source_end, line_end); + + string token = peek_token(); + if(token=="pragma") + preprocess_pragma(); + else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" || + token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="version" || token=="line") + throw runtime_error(format_error(format("Unsupported preprocessor directive '%s'", token))); + else if(!token.empty()) + throw runtime_error(format_syntax_error("a preprocessor directive")); + + iter = line_end; +} + +void ProgramParser::preprocess_pragma() +{ + expect("pragma"); + string token = parse_token(); + if(token=="MSP") + preprocess_pragma_msp(); +} + +void ProgramParser::preprocess_pragma_msp() +{ + string token = peek_token(); + if(token=="stage") + preprocess_stage(); + else + throw runtime_error(format_error(format("Unrecognized MSP pragma '%s'", token))); + + token = parse_token(); + if(!token.empty()) + throw runtime_error(format_syntax_error("end of line")); +} + +void ProgramParser::preprocess_stage() +{ + if(!allow_stage_change) + throw runtime_error(format_error("Changing stage not allowed here")); + + expect("stage"); + expect("("); + string token = expect_identifier(); + StageType stage = SHARED; + if(token=="vertex") + stage = VERTEX; + else if(token=="geometry") + stage = GEOMETRY; + else if(token=="fragment") + stage = FRAGMENT; + else + throw runtime_error(format_syntax_error("stage identifier")); + expect(")"); + + if(stage<=cur_stage->type) + throw runtime_error(format_error(format("Stage '%s' not allowed here", token))); + + module->stages.push_back(stage); + + if(cur_stage->type!=SHARED) + module->stages.back().previous = cur_stage; + cur_stage = &module->stages.back(); +} + RefPtr ProgramParser::parse_global_declaration() { + allow_stage_change = true; string token = peek_token(); + allow_stage_change = false; + if(token=="import") return parse_import(); else if(token=="precision") diff --git a/source/programparser.h b/source/programparser.h index be6da197..fa37118d 100644 --- a/source/programparser.h +++ b/source/programparser.h @@ -40,6 +40,9 @@ private: std::string source_name; unsigned current_line; std::string::const_iterator iter; + std::string::const_iterator source_end; + bool allow_preprocess; + bool allow_stage_change; std::string last_token; std::deque next_tokens; ProgramSyntax::Module *module; @@ -67,7 +70,7 @@ private: std::string parse_identifier(); std::string parse_number(); std::string parse_other(); - bool skip_comment_and_whitespace(); + void skip_comment_and_whitespace(); void expect(const std::string &); std::string expect_type(); std::string expect_identifier(); @@ -81,6 +84,11 @@ private: bool is_type(const std::string &); bool is_identifier(const std::string &); + void preprocess(); + void preprocess_pragma(); + void preprocess_pragma_msp(); + void preprocess_stage(); + RefPtr parse_global_declaration(); RefPtr parse_statement(); RefPtr parse_import();