From: Mikko Rasa Date: Thu, 21 Dec 2023 21:51:37 +0000 (+0200) Subject: Refactor interface generation to carry more explicit information X-Git-Url: https://git.tdb.fi/?a=commitdiff_plain;h=9f53f6616c2b382765a23d3161013d65a6080c56;p=libs%2Fgl.git Refactor interface generation to carry more explicit information --- diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp index e9b1e95a..dc5e7a22 100644 --- a/source/glsl/compiler.cpp +++ b/source/glsl/compiler.cpp @@ -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(), + run()); + for_stages(run(), resolve(RESOLVE_BLOCKS|RESOLVE_TYPES|RESOLVE_VARIABLES), run(), run(), diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 10e19240..c203c21a 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -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 &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 &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 &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 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 ref = make_unique(); - ref->name = v->name; + ref->name = src_name; if(pass.subscript) { unique_ptr subscript = make_unique(); 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); diff --git a/source/glsl/generate.h b/source/glsl/generate.h index 190d3ecf..fac9bc6a 100644 --- a/source/glsl/generate.h +++ b/source/glsl/generate.h @@ -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 declared_inputs; + std::vector declared_inputs; Block *iface_target_block = nullptr; NodeList::iterator iface_insert_point; NodeList::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); diff --git a/source/glsl/syntax.h b/source/glsl/syntax.h index bc598204..0b851ab4 100644 --- a/source/glsl/syntax.h +++ b/source/glsl/syntax.h @@ -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 locations; std::map texture_bindings; std::map uniform_block_bindings; + std::map potential_outs; unsigned n_clip_distances = 0; Features required_features; std::vector diagnostics;