]> git.tdb.fi Git - libs/gl.git/commitdiff
Refactor interface generation to carry more explicit information
authorMikko Rasa <tdb@tdb.fi>
Thu, 21 Dec 2023 21:51:37 +0000 (23:51 +0200)
committerMikko Rasa <tdb@tdb.fi>
Thu, 21 Dec 2023 21:51:37 +0000 (23:51 +0200)
source/glsl/compiler.cpp
source/glsl/generate.cpp
source/glsl/generate.h
source/glsl/syntax.h

index e9b1e95a41cd549fd33872fda2d43d84632f0190..dc5e7a2219b0c599e4474e8a086a42a466158cd8 100644 (file)
@@ -132,7 +132,8 @@ void Compiler::compile(Mode mode)
        // Generate any implicitly defined syntactic structures
        for_stages([this](Stage &s){ compose(s); },
                resolve(RESOLVE_ALL),
-               run<InterfaceGenerator>(),
+               run<PotentialInterfaceCollector>());
+       for_stages(run<InterfaceGenerator>(),
                resolve(RESOLVE_BLOCKS|RESOLVE_TYPES|RESOLVE_VARIABLES),
                run<LayoutDefaulter>(),
                run<ArraySizer>(),
index 10e19240289c5b4d004aa637219dcd85e555be5a..c203c21a9f641cdef2986dcfb75333f692bc508d 100644 (file)
@@ -56,7 +56,29 @@ void ConstantIdAssigner::visit(VariableDeclaration &var)
 }
 
 
-string InterfaceGenerator::get_out_prefix(Stage::Type type)
+void PotentialInterfaceCollector::apply(Stage &s)
+{
+       stage = &s;
+       out_prefix = get_out_prefix(stage->type);
+       s.content.visit(*this);
+       if(stage->previous)
+       {
+               for(auto &kvp: stage->previous->potential_outs)
+                       if(!stage->potential_outs.count(kvp.first))
+                       {
+                               PotentialInterface &pot_out = stage->potential_outs[kvp.first];
+                               pot_out.name = kvp.first;
+                               if(!kvp.second.block_member)
+                                       pot_out.link_name = out_prefix+kvp.first;
+                               pot_out.block_member = kvp.second.block_member;
+                               pot_out.passthrough = true;
+                               pot_out.referenced = false;
+                               pot_out.chained_from = &kvp.second;
+                       }
+       }
+}
+
+string PotentialInterfaceCollector::get_out_prefix(Stage::Type type)
 {
        if(type==Stage::VERTEX)
                return "_vs_out_";
@@ -66,13 +88,54 @@ string InterfaceGenerator::get_out_prefix(Stage::Type type)
                return string();
 }
 
+void PotentialInterfaceCollector::visit(VariableReference &var)
+{
+       if(var.declaration || !stage->previous)
+               return;
+
+       auto i = stage->previous->potential_outs.find(var.name);
+       if(i!=stage->previous->potential_outs.end())
+       {
+               for(PotentialInterface *p=&i->second; p; p=p->chained_from)
+                       p->referenced = true;
+       }
+}
+
+void PotentialInterfaceCollector::visit(StructDeclaration &strct)
+{
+       SetForScope set_block(current_block, strct.block_declaration);
+       TraversingVisitor::visit(strct);
+}
+
+void PotentialInterfaceCollector::visit(VariableDeclaration &var)
+{
+       const string &iface = (current_block ? current_block->interface : var.interface);
+       bool builtin = (!var.name.compare(0, 3, "gl_") || (var.block_declaration && !var.block_declaration->block_name.compare(0, 3, "gl_")));
+       if(stage->type!=Stage::FRAGMENT && !builtin && (iface=="in" || iface=="out") &&
+               (!current_block || current_block->name.find(' ')!=string::npos))
+       {
+               PotentialInterface &pot_out = stage->potential_outs[var.name];
+               pot_out.name = var.name;
+               if(current_block)
+                       pot_out.link_name.clear();
+               else if(var.interface=="in")
+                       pot_out.link_name = out_prefix+var.name;
+               else
+                       pot_out.link_name = var.name;
+               pot_out.block_member = current_block;
+               pot_out.passthrough = (iface=="in");
+               pot_out.referenced = false;
+               pot_out.declaration = (current_block ? current_block : &var);
+       }
+
+       TraversingVisitor::visit(var);
+}
+
+
 void InterfaceGenerator::apply(Stage &s)
 {
        stage = &s;
        iface_target_block = &stage->content;
-       if(stage->previous)
-               in_prefix = get_out_prefix(stage->previous->type);
-       out_prefix = get_out_prefix(stage->type);
        s.content.visit(*this);
        NodeRemover().apply(s, nodes_to_remove);
 }
@@ -90,12 +153,6 @@ void InterfaceGenerator::visit(Block &block)
        }
 }
 
-string InterfaceGenerator::change_prefix(const string &name, const string &prefix) const
-{
-       unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size());
-       return prefix+name.substr(offset);
-}
-
 VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration &other_var, const string &iface, const string &name)
 {
        if(stage->content.variables.count(name))
@@ -153,7 +210,7 @@ VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration
 
        iface_target_block->variables.insert(make_pair(name, var.get()));
        if(iface_target_block==&stage->content && iface=="in")
-               declared_inputs.push_back(var.get());
+               declared_inputs.push_back(name);
 
        VariableDeclaration *result = var.get();
        iface_target_block->body.insert(iface_insert_point, move(var));
@@ -202,34 +259,14 @@ void InterfaceGenerator::visit(VariableReference &var)
        if(stage->content.variables.count(var.name))
                return;
 
-       const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
-       auto i = prev_vars.find(var.name);
-       if(i==prev_vars.end() || i->second->interface!="out")
-               i = prev_vars.find(in_prefix+var.name);
-       if(i!=prev_vars.end() && i->second->interface=="out")
+       map<string, PotentialInterface> &prev_outs = stage->previous->potential_outs;
+       auto j = prev_outs.find(var.name);
+       if(j!=prev_outs.end() && j->second.declaration && j->second.declaration->interface=="out")
        {
-               if(stage->type==Stage::GEOMETRY && i->second->array)
-                       stage->diagnostics.emplace_back(Diagnostic::WARN, var.source, var.line,
-                               format("Can't access '%s' through automatic interface because it's an array", var.name));
-               else
-               {
-                       generate_interface(*i->second, "in", i->second->name);
-                       var.name = i->second->name;
-               }
-               return;
+               generate_interface(*j->second.declaration, "in", j->second.link_name);
+               if(!j->second.block_member)
+                       var.name = j->second.link_name;
        }
-
-       for(const auto &kvp: stage->previous->interface_blocks)
-               if(kvp.second->name.find(' ')!=string::npos)
-               {
-                       const map<string, VariableDeclaration *> &block_vars = kvp.second->block_declaration->members.variables;
-                       i = block_vars.find(var.name);
-                       if(i!=block_vars.end())
-                       {
-                               generate_interface(*kvp.second, "in", string());
-                               return;
-                       }
-               }
 }
 
 void InterfaceGenerator::visit(VariableDeclaration &var)
@@ -241,6 +278,10 @@ void InterfaceGenerator::visit(VariableDeclaration &var)
                VariableDeclaration *out_var = nullptr;
                if(function_scope && (out_var=generate_interface(var, "out", var.name)))
                {
+                       auto i = stage->potential_outs.find(var.name);
+                       if(i!=stage->potential_outs.end())
+                               i->second.declaration = out_var;
+
                        out_var->source = var.source;
                        out_var->line = var.line;
                        nodes_to_remove.insert(&var);
@@ -256,7 +297,7 @@ void InterfaceGenerator::visit(VariableDeclaration &var)
        else if(var.interface=="in" && current_block==&stage->content)
        {
                if(var.name.compare(0, 3, "gl_"))
-                       declared_inputs.push_back(&var);
+                       declared_inputs.push_back(var.name);
 
                /* Try to link input variables in global scope with output variables from
                previous stage. */
@@ -297,23 +338,6 @@ void InterfaceGenerator::visit(FunctionDeclaration &func)
 
 void InterfaceGenerator::visit(Passthrough &pass)
 {
-       // Pass through all input variables declared so far.
-       vector<VariableDeclaration *> pass_vars = declared_inputs;
-
-       if(stage->previous)
-       {
-               for(const auto &kvp: stage->previous->content.variables)
-               {
-                       if(kvp.second->interface!="out")
-                               continue;
-
-                       /* Pass through output variables from the previous stage, but only
-                       those which are not already linked to an input here. */
-                       if(!kvp.second->linked_declaration && generate_interface(*kvp.second, "in", kvp.second->name))
-                               pass_vars.push_back(kvp.second);
-               }
-       }
-
        if(stage->type==Stage::GEOMETRY)
        {
                /* Special case for geometry shader: copy gl_Position from input to
@@ -333,23 +357,35 @@ void InterfaceGenerator::visit(Passthrough &pass)
                insert_assignment("out gl_PerVertex.gl_Position", move(memacc));
        }
 
-       for(VariableDeclaration *v: pass_vars)
+       for(auto &kvp: stage->potential_outs)
        {
-               string out_name = change_prefix(v->name, out_prefix);
-               generate_interface(*v, "out", out_name);
+               if(!kvp.second.referenced || !kvp.second.passthrough)
+                       continue;
+
+               if(!kvp.second.declaration && kvp.second.chained_from && kvp.second.chained_from->declaration)
+                       kvp.second.declaration = generate_interface(*kvp.second.chained_from->declaration, "in", kvp.second.chained_from->link_name);
+               if(!kvp.second.declaration)
+                       continue;
+
+               if(kvp.second.declaration->interface!="out")
+                       kvp.second.declaration = generate_interface(*kvp.second.declaration, "out", kvp.second.link_name);
+
+               string src_name = (kvp.second.chained_from ? kvp.second.chained_from->link_name : kvp.second.name);
+               if(!any_equals(declared_inputs, src_name))
+                       continue;
 
                unique_ptr<VariableReference> ref = make_unique<VariableReference>();
-               ref->name = v->name;
+               ref->name = src_name;
                if(pass.subscript)
                {
                        unique_ptr<BinaryExpression> subscript = make_unique<BinaryExpression>();
                        subscript->left = move(ref);
                        subscript->oper = &Operator::get_operator("[", Operator::BINARY);
                        subscript->right = pass.subscript.clone();
-                       insert_assignment(out_name, move(subscript));
+                       insert_assignment(kvp.second.link_name, move(subscript));
                }
                else
-                       insert_assignment(out_name, move(ref));
+                       insert_assignment(kvp.second.link_name, move(ref));
        }
 
        nodes_to_remove.insert(&pass);
index 190d3ecfe13c826f28fdfb64df5db1a73bbe10dd..fac9bc6a34cb8b06f6b8e10b0ec5390547714f4f 100644 (file)
@@ -26,6 +26,25 @@ private:
        void visit(VariableDeclaration &) override;
 };
 
+/** Collects declared output variables as well as those which can be generated
+from inputs.  Marks outputs which are referenced by later stages. */
+class PotentialInterfaceCollector: private TraversingVisitor
+{
+private:
+       Stage *stage = nullptr;
+       std::string out_prefix;
+       VariableDeclaration *current_block = nullptr;
+
+public:
+       void apply(Stage &);
+
+private:
+       static std::string get_out_prefix(Stage::Type);
+       virtual void visit(VariableReference &);
+       virtual void visit(StructDeclaration &);
+       virtual void visit(VariableDeclaration &);
+};
+
 /** Materializes implicitly declared interfaces.
 
 Out variable declarations inside functions are moved to the global scope.
@@ -38,11 +57,9 @@ class InterfaceGenerator: private TraversingVisitor
 {
 private:
        Stage *stage = nullptr;
-       std::string in_prefix;
-       std::string out_prefix;
        bool function_scope = false;
        bool copy_block = false;
-       std::vector<VariableDeclaration *> declared_inputs;
+       std::vector<std::string> declared_inputs;
        Block *iface_target_block = nullptr;
        NodeList<Statement>::iterator iface_insert_point;
        NodeList<Statement>::iterator assignment_insert_point;
@@ -52,8 +69,6 @@ public:
        void apply(Stage &);
 
 private:
-       static std::string get_out_prefix(Stage::Type);
-       std::string change_prefix(const std::string &, const std::string &) const;
        void visit(Block &) override;
        VariableDeclaration *generate_interface(VariableDeclaration &, const std::string &, const std::string &);
        ExpressionStatement &insert_assignment(const std::string &, std::unique_ptr<Expression>);
index bc5982045f91ee28309f598ebdf7592bd16087d4..0b851ab45a7212808e57464a5780cdc82124873b 100644 (file)
@@ -542,6 +542,17 @@ struct Jump: Statement
        void visit(NodeVisitor &) override;
 };
 
+struct PotentialInterface
+{
+       std::string name;
+       std::string link_name;
+       VariableDeclaration *declaration = nullptr;
+       PotentialInterface *chained_from = nullptr;
+       bool block_member = false;
+       bool passthrough = false;
+       bool referenced = false;
+};
+
 struct Stage
 {
        enum Type
@@ -564,6 +575,7 @@ struct Stage
        std::map<std::string, unsigned> locations;
        std::map<std::string, unsigned> texture_bindings;
        std::map<std::string, unsigned> uniform_block_bindings;
+       std::map<std::string, PotentialInterface> potential_outs;
        unsigned n_clip_distances = 0;
        Features required_features;
        std::vector<Diagnostic> diagnostics;