]> git.tdb.fi Git - libs/gl.git/commitdiff
Generalize shader interface handling
authorMikko Rasa <tdb@tdb.fi>
Thu, 15 May 2014 21:59:26 +0000 (00:59 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 15 May 2014 21:59:26 +0000 (00:59 +0300)
source/programbuilder.cpp
source/programbuilder.h

index 28acc5d941f2f24405bc1d5302e795ecb348c8b1..67aaf57047ec08db186956b73120ac58c7f348a3 100644 (file)
@@ -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<ShaderVariable *> &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<ShaderVariable *>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
        {
-               const char *qualifier = (features.legacy ? "attribute" : "in");
-               for(list<ShaderVariable *>::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<ShaderVariable *> varyings;
-       for(list<ShaderVariable *>::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<ShaderVariable *>::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<ShaderVariable *>::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<ShaderVariable *>::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<ShaderVariable *>::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->scope<scope)
+                       if(!inlined || variable->scope!=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<InterfaceFlags>(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();
index 821907d5dba46a281323c3364e1b85095426296e..69170e02ef979f543b16f1fc53ef0c9adbc0c2d1 100644 (file)
@@ -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 &);