From: Mikko Rasa Date: Thu, 15 May 2014 21:59:26 +0000 (+0300) Subject: Generalize shader interface handling X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=d542522823423f9ed2a5d412de9250ee8367334b;p=libs%2Fgl.git Generalize shader interface handling --- diff --git a/source/programbuilder.cpp b/source/programbuilder.cpp index 28acc5d9..67aaf570 100644 --- a/source/programbuilder.cpp +++ b/source/programbuilder.cpp @@ -124,6 +124,8 @@ const ProgramBuilder::VariableDefinition ProgramBuilder::standard_variables[] = { NO_SCOPE, 0, 0, 0, 0 } }; +const char ProgramBuilder::interfaces[] = { 0, 0, 0, 'v', 0 }; + ProgramBuilder::ProgramBuilder(const StandardFeatures &f): features(f), feature_flags(features.create_flags()), @@ -327,54 +329,43 @@ string ProgramBuilder::create_source(const list &variables, Va if((*i)->variable->scope==UNIFORM && (*i)->is_referenced_from(scope) && !(*i)->inlined) source += format("uniform %s;\n", (*i)->create_declaration()); - if(scope==VERTEX) + /* Interface variables need to have global declarations. */ + for(list::const_iterator i=variables.begin(); i!=variables.end(); ++i) { - const char *qualifier = (features.legacy ? "attribute" : "in"); - for(list::const_iterator i=variables.begin(); i!=variables.end(); ++i) - if((*i)->variable->scope==ATTRIBUTE && !(*i)->inlined) - source += format("%s %s;\n", qualifier, (*i)->create_declaration()); - } + if(!(*i)->resolved_name.compare(0, 3, "gl_")) + continue; - /* Any variables defined in vertex scope but referenced from fragment scope - should be exported as varyings over the interface. */ - list varyings; - for(list::const_iterator i=variables.begin(); i!=variables.end(); ++i) - if(((*i)->variable->scope==VERTEX || (*i)->variable->scope==ATTRIBUTE) && (*i)->is_referenced_from(FRAGMENT)) + InterfaceFlags interface = (*i)->get_interface_flags(scope); + + if(interface&INPUT) { - varyings.push_back(*i); - const char *qualifier; - if(!features.legacy) - qualifier = (scope==VERTEX ? "out" : "in"); - else - qualifier = "varying"; - source += format("%s %s;\n", qualifier, (*i)->create_declaration('v')); + const char *qualifier = (features.legacy ? scope==VERTEX ? "attribute" : "varying" : "in"); + source += format("%s %s;\n", qualifier, (*i)->create_declaration(interfaces[scope-1])); } - for(list::const_iterator i=variables.begin(); i!=variables.end(); ++i) - if((*i)->referenced_by.empty() && (*i)->resolved_name.compare(0, 3, "gl_")) - source += format("out %s;\n", (*i)->create_declaration()); + if(interface&OUTPUT) + { + const char *qualifier = (features.legacy ? "varying" : "out"); + source += format("%s %s;\n", qualifier, (*i)->create_declaration(interfaces[scope])); + } + } source += "void main()\n{\n"; for(list::const_iterator i=variables.begin(); i!=variables.end(); ++i) + { + InterfaceFlags interface = (*i)->get_interface_flags(scope); + if((*i)->variable->scope==scope && !(*i)->inlined) { - source += '\t'; - if((*i)->referenced_by.empty()) - source += (*i)->resolved_name; - else - source += (*i)->create_declaration(); - source += format(" = %s;\n", (*i)->create_expression()); + string decl = ((interface&GOAL) ? (*i)->resolved_name : (*i)->create_declaration()); + source += format("\t%s = %s;\n", decl, (*i)->create_expression()); } - if(scope==VERTEX) - { - for(list::const_iterator i=varyings.begin(); i!=varyings.end(); ++i) + if((interface&(OUTPUT|GOAL))==OUTPUT) { - if((*i)->inlined) - source += format("\tv_%s = %s;\n", (*i)->resolved_name, (*i)->create_expression()); - else - source += format("\tv_%s = %s;\n", (*i)->resolved_name, (*i)->resolved_name); + string expr = ((*i)->inlined ? (*i)->create_expression() : (*i)->resolved_name); + source += format("\t%c_%s = %s;\n", interfaces[scope], (*i)->resolved_name, expr); } } @@ -672,6 +663,33 @@ bool ProgramBuilder::ShaderVariable::is_referenced_from(VariableScope scope) con return false; } +ProgramBuilder::InterfaceFlags ProgramBuilder::ShaderVariable::get_interface_flags(VariableScope scope) const +{ + /* Uniforms are available to all stages and are not passed through + interfaces */ + if(variable->scope==UNIFORM) + return NO_INTERFACE; + + int flags = NO_INTERFACE; + + for(list::const_iterator i=referenced_by.begin(); i!=referenced_by.end(); ++i) + { + /* Variables used in a later scope than they are declared in need to go + through the interface */ + if((*i)->variable->scope>scope && variable->scope<=scope) + flags |= OUTPUT; + if((*i)->variable->scope>=scope && variable->scopescope!=ATTRIBUTE || scope!=VERTEX) + flags |= INPUT; + } + + // Variables without any references are goals and also outputs. + if(referenced_by.empty() && variable->scope==scope) + flags |= OUTPUT|GOAL; + + return static_cast(flags); +} + string ProgramBuilder::ShaderVariable::create_declaration(char interface) const { if(variable->scope==UNIFORM) @@ -692,8 +710,9 @@ string ProgramBuilder::ShaderVariable::create_replacement(VariableScope from_sco string replacement = resolved_name; if(variable) { - if(from_scope==FRAGMENT && (variable->scope==VERTEX || variable->scope==ATTRIBUTE)) - replacement = "v_"+replacement; + InterfaceFlags interface = get_interface_flags(from_scope); + if((interface&INPUT) && interfaces[from_scope-1]) + replacement = format("%c_%s", interfaces[from_scope-1], replacement); else if(inlined) { replacement = create_expression(); diff --git a/source/programbuilder.h b/source/programbuilder.h index 821907d5..69170e02 100644 --- a/source/programbuilder.h +++ b/source/programbuilder.h @@ -54,6 +54,15 @@ private: FRAGMENT }; + enum InterfaceFlags + { + NO_INTERFACE = 0, + INPUT = 1, + OUTPUT = 2, + PASSTHROUGH = INPUT|OUTPUT, + GOAL = 4 + }; + struct VariableDefinition { VariableScope scope; @@ -84,6 +93,7 @@ private: void update_reference(ShaderVariable &, ShaderVariable &); void check_inline(bool, bool); bool is_referenced_from(VariableScope) const; + InterfaceFlags get_interface_flags(VariableScope) const; std::string create_declaration(char = 0) const; std::string create_replacement(VariableScope) const; std::string create_expression() const; @@ -102,6 +112,7 @@ private: bool optimize; static const VariableDefinition standard_variables[]; + static const char interfaces[]; public: ProgramBuilder(const StandardFeatures &);