From 041ba4b1acd55337239c5ce24cc310118c621206 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 8 Mar 2021 15:06:01 +0200 Subject: [PATCH] Transform interface block contents into structs This allows handling them in expression trees like everything else. It also helps with SPIR-V, which requires interface blocks to have struct types. --- source/glsl/compatibility.cpp | 11 +++- source/glsl/compiler.cpp | 5 +- source/glsl/debug.cpp | 12 +++- source/glsl/generate.cpp | 102 ++++++++++++++++++---------------- source/glsl/generate.h | 4 +- source/glsl/optimize.cpp | 19 ++++++- source/glsl/optimize.h | 1 + source/glsl/output.cpp | 8 +-- source/glsl/output.h | 1 - source/glsl/parser.cpp | 3 +- source/glsl/syntax.cpp | 25 +++++++-- source/glsl/syntax.h | 11 +++- source/glsl/validate.cpp | 16 +++++- source/glsl/validate.h | 1 + source/glsl/visitor.cpp | 3 +- 15 files changed, 148 insertions(+), 74 deletions(-) diff --git a/source/glsl/compatibility.cpp b/source/glsl/compatibility.cpp index a5ba8247..3700a9c9 100644 --- a/source/glsl/compatibility.cpp +++ b/source/glsl/compatibility.cpp @@ -341,15 +341,20 @@ bool LegacyConverter::supports_interface_blocks(const string &iface) const void LegacyConverter::visit(InterfaceBlock &iface) { - if(!supports_interface_blocks(iface.interface)) + if(!supports_interface_blocks(iface.interface) && iface.type_declaration) { if(!iface.instance_name.empty()) unsupported("ARB_uniform_buffer_object required for interface block instances"); - else + else if(iface.struct_declaration) { - stage->content.body.splice(uniform_insert_point, iface.members.body); + stage->content.body.splice(uniform_insert_point, iface.struct_declaration->members.body); nodes_to_remove.insert(&iface); + nodes_to_remove.insert(iface.struct_declaration); } + else + /* If the interface block is an array, it should have an instance + name too, so this should never be reached */ + throw logic_error("Unexpected interface block configuration"); } } diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp index ac014a00..ccfbe691 100644 --- a/source/glsl/compiler.cpp +++ b/source/glsl/compiler.cpp @@ -166,7 +166,8 @@ string Compiler::get_diagnostics() const string combined; for(list::const_iterator i=module->stages.begin(); i!=module->stages.end(); ++i) for(vector::const_iterator j=i->diagnostics.begin(); j!=i->diagnostics.end(); ++j) - append(combined, "\n", format("%s:%d: %s", module->source_map.get_name(j->source), j->line, j->message)); + if(j->source!=INTERNAL_SOURCE) + append(combined, "\n", format("%s:%d: %s", module->source_map.get_name(j->source), j->line, j->message)); return combined; } @@ -275,7 +276,7 @@ void Compiler::resolve(Stage &stage, unsigned flags) if(resolve(stage, flags, RESOLVE_BLOCKS)) ; else if(resolve(stage, flags, RESOLVE_TYPES)) - flags |= RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS; + flags |= RESOLVE_BLOCKS|RESOLVE_VARIABLES|RESOLVE_EXPRESSIONS; else if(resolve(stage, flags, RESOLVE_VARIABLES)) flags |= RESOLVE_EXPRESSIONS; else if(resolve(stage, flags, RESOLVE_FUNCTIONS)) diff --git a/source/glsl/debug.cpp b/source/glsl/debug.cpp index ed604fff..ee50bf46 100644 --- a/source/glsl/debug.cpp +++ b/source/glsl/debug.cpp @@ -165,7 +165,7 @@ void DumpTree::visit(InterfaceBlockReference &iface) string text; if(iface.declaration) text += format("%%%d ", get_label(*iface.declaration)); - text += format("%s (iface)", iface.name); + text += format("%s (iface) -> %s", iface.name, format_type(iface.type)); append(text); } @@ -346,7 +346,15 @@ void DumpTree::visit(InterfaceBlock &block) head += " (builtin)"; else if(block.linked_block) head += " (linked)"; - annotated_branch(head, block.members); + append(head); + + begin_sub(); + last_branch(); + if(block.type_declaration) + append(format("Type: %%%d %s", get_label(*block.type_declaration), block.type_declaration->name)); + else if(block.members) + block.members->visit(*this); + end_sub(); } void DumpTree::visit(FunctionDeclaration &func) diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 4fd8c6ab..53676c26 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -123,6 +123,7 @@ void BlockHierarchyResolver::enter(Block &block) TypeResolver::TypeResolver(): stage(0), + iface_block(0), r_any_resolved(false) { } @@ -214,6 +215,34 @@ void TypeResolver::visit(StructDeclaration &strct) void TypeResolver::visit(VariableDeclaration &var) { resolve_type(var.type_declaration, var.type, var.array); + if(iface_block && var.interface==iface_block->interface) + var.interface.clear(); +} + +void TypeResolver::visit(InterfaceBlock &iface) +{ + if(iface.members) + { + SetForScope set_iface(iface_block, &iface); + iface.members->visit(*this); + + StructDeclaration *strct = new StructDeclaration; + strct->source = INTERNAL_SOURCE; + strct->name = format("_%s_%s", iface.interface, iface.name); + strct->members.body.splice(strct->members.body.begin(), iface.members->body); + stage->content.body.insert(type_insert_point, strct); + stage->types.insert(make_pair(strct->name, strct)); + + iface.members = 0; + strct->interface_block = &iface; + iface.struct_declaration = strct; + } + + TypeDeclaration *type = iface.struct_declaration; + if(type && iface.array) + type = get_or_create_array_type(*type); + r_any_resolved = (type!=iface.type_declaration); + iface.type_declaration = type; } void TypeResolver::visit(FunctionDeclaration &func) @@ -250,7 +279,10 @@ void VariableResolver::visit_and_replace(RefPtr &expr) r_replacement_expr = 0; expr->visit(*this); if(r_replacement_expr) + { expr = r_replacement_expr; + r_any_resolved = true; + } r_replacement_expr = 0; } @@ -287,10 +319,11 @@ void VariableResolver::visit(VariableReference &var) { // Look for the variable in anonymous interface blocks. for(i=blocks.begin(); (!declaration && i!=blocks.end()); ++i) - if(i->second->instance_name.empty()) + if(i->second->instance_name.empty() && i->second->struct_declaration) { - map::iterator j = i->second->members.variables.find(var.name); - if(j!=i->second->members.variables.end()) + const map &iface_vars = i->second->struct_declaration->members.variables; + map::const_iterator j = iface_vars.find(var.name); + if(j!=iface_vars.end()) declaration = j->second; } } @@ -327,20 +360,11 @@ void VariableResolver::visit(MemberAccess &memacc) { visit_and_replace(memacc.left); - map *members = 0; - if(StructDeclaration *strct = dynamic_cast(memacc.left->type)) - members = &strct->members.variables; - else if(InterfaceBlockReference *iface_ref = dynamic_cast(memacc.left.get())) - { - if(iface_ref->declaration) - members = &iface_ref->declaration->members.variables; - } - VariableDeclaration *declaration = 0; - if(members) + if(StructDeclaration *strct = dynamic_cast(memacc.left->type)) { - map::iterator i = members->find(memacc.member); - if(i!=members->end()) + map::iterator i = strct->members.variables.find(memacc.member); + if(i!=strct->members.variables.end()) declaration = i->second; } @@ -395,9 +419,6 @@ void VariableResolver::visit(FunctionCall &call) void VariableResolver::visit(VariableDeclaration &var) { - if(!block_interface.empty() && var.interface.empty()) - var.interface = block_interface; - if(var.layout) var.layout->visit(*this); if(var.array_size) @@ -415,7 +436,6 @@ void VariableResolver::visit(InterfaceBlock &iface) if(!iface.instance_name.empty()) stage->interface_blocks.insert(make_pair("_"+iface.instance_name, &iface)); - SetForScope set_iface(block_interface, iface.interface); TraversingVisitor::visit(iface); } @@ -557,7 +577,8 @@ void ExpressionResolver::visit(VariableReference &var) void ExpressionResolver::visit(InterfaceBlockReference &iface) { - resolve(iface, 0, true); + if(iface.declaration) + resolve(iface, iface.declaration->type_declaration, true); } void ExpressionResolver::visit(MemberAccess &memacc) @@ -861,7 +882,6 @@ void FunctionResolver::visit(FunctionDeclaration &func) InterfaceGenerator::InterfaceGenerator(): stage(0), function_scope(false), - iface_block(0), copy_block(false), iface_target_block(0) { } @@ -945,6 +965,7 @@ InterfaceBlock *InterfaceGenerator::generate_interface(InterfaceBlock &out_block InterfaceBlock *in_block = new InterfaceBlock; in_block->interface = "in"; in_block->name = out_block.name; + in_block->members = new Block; in_block->instance_name = out_block.instance_name; if(stage->type==Stage::GEOMETRY) in_block->array = true; @@ -955,9 +976,12 @@ InterfaceBlock *InterfaceGenerator::generate_interface(InterfaceBlock &out_block { SetFlag set_copy(copy_block, true); - SetForScope set_target(iface_target_block, &in_block->members); - SetForScope::iterator> set_ins_pt(iface_insert_point, in_block->members.body.end()); - out_block.members.visit(*this); + SetForScope set_target(iface_target_block, in_block->members.get()); + SetForScope::iterator> set_ins_pt(iface_insert_point, in_block->members->body.end()); + if(out_block.struct_declaration) + out_block.struct_declaration->members.visit(*this); + else if(out_block.members) + out_block.members->visit(*this); } iface_target_block->body.insert(iface_insert_point, in_block); @@ -1020,10 +1044,11 @@ void InterfaceGenerator::visit(VariableReference &var) } for(j=prev_blocks.begin(); j!=prev_blocks.end(); ++j) - if(j->second->instance_name.empty()) + if(j->second->instance_name.empty() && j->second->struct_declaration) { - i = j->second->members.variables.find(var.name); - if(i!=j->second->members.variables.end()) + const map &iface_vars = j->second->struct_declaration->members.variables; + i = iface_vars.find(var.name); + if(i!=iface_vars.end()) { generate_interface(*j->second); return; @@ -1034,28 +1059,8 @@ void InterfaceGenerator::visit(VariableReference &var) void InterfaceGenerator::visit(VariableDeclaration &var) { if(copy_block) - { generate_interface(var, "in", var.name); - return; - } - - if(iface_block) - { - if(iface_block->linked_block) - { - // Link all variables to their counterparts in the linked block. - const map &linked_vars = iface_block->linked_block->members.variables; - map::const_iterator i = linked_vars.find(var.name); - if(i!=linked_vars.end()) - { - var.linked_declaration = i->second; - var.linked_declaration->linked_declaration = &var; - } - } - return; - } - - if(var.interface=="out") + else if(var.interface=="out") { /* For output variables in function scope, generate a global interface and replace the local declaration with an assignment. */ @@ -1111,7 +1116,6 @@ void InterfaceGenerator::visit(InterfaceBlock &iface) } } - SetForScope set_iface(iface_block, &iface); TraversingVisitor::visit(iface); } diff --git a/source/glsl/generate.h b/source/glsl/generate.h index a728e99c..427f4de2 100644 --- a/source/glsl/generate.h +++ b/source/glsl/generate.h @@ -68,6 +68,7 @@ private: std::map alias_map; std::map array_types; NodeList::iterator type_insert_point; + InterfaceBlock *iface_block; bool r_any_resolved; public: @@ -83,6 +84,7 @@ private: virtual void visit(ImageTypeDeclaration &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); }; @@ -93,7 +95,6 @@ class VariableResolver: private TraversingVisitor private: Stage *stage; RefPtr r_replacement_expr; - std::string block_interface; bool r_any_resolved; bool record_target; bool r_self_referencing; @@ -196,7 +197,6 @@ private: std::string in_prefix; std::string out_prefix; bool function_scope; - InterfaceBlock *iface_block; bool copy_block; Block *iface_target_block; NodeList::iterator iface_insert_point; diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index f9383148..c1431f2b 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -668,6 +668,11 @@ void UnusedTypeRemover::visit(VariableDeclaration &var) unused_nodes.erase(var.type_declaration); } +void UnusedTypeRemover::visit(InterfaceBlock &iface) +{ + unused_nodes.erase(iface.type_declaration); +} + void UnusedTypeRemover::visit(FunctionDeclaration &func) { unused_nodes.erase(func.return_type_declaration); @@ -690,9 +695,19 @@ bool UnusedVariableRemover::apply(Stage &stage) BlockVariableMap &global_variables = variables.back(); for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i) { + string interface = i->first->interface; + bool linked = i->first->linked_declaration; + map::iterator j = aggregates.find(i->first); + if(j!=aggregates.end()) + if(InterfaceBlock *iface = dynamic_cast(j->second)) + { + interface = iface->interface; + linked = iface->linked_block; + } + /* Don't remove output variables which are used by the next stage or the graphics API. */ - if(i->first->interface=="out" && (stage.type==Stage::FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_"))) + if(interface=="out" && (stage.type==Stage::FRAGMENT || linked || !i->first->name.compare(0, 3, "gl_"))) continue; // Mark other unreferenced global variables as unused. @@ -833,7 +848,7 @@ void UnusedVariableRemover::visit(InterfaceBlock &iface) { SetForScope set(aggregate, &iface); unused_nodes.insert(&iface); - TraversingVisitor::visit(iface); + iface.struct_declaration->members.visit(*this); } void UnusedVariableRemover::visit(FunctionDeclaration &func) diff --git a/source/glsl/optimize.h b/source/glsl/optimize.h index 652ac252..551e2d56 100644 --- a/source/glsl/optimize.h +++ b/source/glsl/optimize.h @@ -184,6 +184,7 @@ private: virtual void visit(ImageTypeDeclaration &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); }; diff --git a/source/glsl/output.cpp b/source/glsl/output.cpp index d44dbff9..52371d1b 100644 --- a/source/glsl/output.cpp +++ b/source/glsl/output.cpp @@ -94,7 +94,7 @@ void Formatter::visit(Block &block) bool first = true; for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) { - if((*i)->source==BUILTIN_SOURCE) + if((*i)->source<=BUILTIN_SOURCE) continue; if(!first) append('\n'); @@ -229,7 +229,7 @@ void Formatter::visit(VariableDeclaration &var) append(format("%s ", var.interpolation)); if(!var.sampling.empty()) append(format("%s ", var.sampling)); - if(!var.interface.empty() && var.interface!=block_interface) + if(!var.interface.empty()) { string interface = var.interface; if(mode==Compiler::PROGRAM && stage && stage->required_features.glsl_version set(block_interface, iface.interface); append(format("%s %s\n", iface.interface, iface.name)); - iface.members.visit(*this); + if(iface.struct_declaration) + iface.struct_declaration->members.visit(*this); if(!iface.instance_name.empty()) { append(' '); diff --git a/source/glsl/output.h b/source/glsl/output.h index 69a99d1e..f720606e 100644 --- a/source/glsl/output.h +++ b/source/glsl/output.h @@ -20,7 +20,6 @@ private: unsigned source_line; unsigned indent; bool parameter_list; - std::string block_interface; public: Formatter(); diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index d2261126..fd782648 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -776,7 +776,8 @@ RefPtr Parser::parse_interface_block() throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier"); iface->name = expect_identifier(); - parse_block(iface->members, true, &Parser::parse_variable_declaration_with_layout); + iface->members = new Block; + parse_block(*iface->members, true, &Parser::parse_variable_declaration_with_layout); if(!check(";")) { iface->instance_name = expect_identifier(); diff --git a/source/glsl/syntax.cpp b/source/glsl/syntax.cpp index d7eec3da..cb774197 100644 --- a/source/glsl/syntax.cpp +++ b/source/glsl/syntax.cpp @@ -272,11 +272,24 @@ void ImageTypeDeclaration::visit(NodeVisitor &visitor) } -StructDeclaration::StructDeclaration() +StructDeclaration::StructDeclaration(): + interface_block(0) { members.use_braces = true; } +StructDeclaration::StructDeclaration(const StructDeclaration &other): + TypeDeclaration(other), + members(other.members), + interface_block(0) +{ } + +StructDeclaration::~StructDeclaration() +{ + if(interface_block && interface_block->struct_declaration==this) + interface_block->struct_declaration = 0; +} + void StructDeclaration::visit(NodeVisitor &visitor) { visitor.visit(*this); @@ -321,10 +334,10 @@ void VariableDeclaration::visit(NodeVisitor &visitor) InterfaceBlock::InterfaceBlock(): array(false), + type_declaration(0), + struct_declaration(0), linked_block(0) -{ - members.use_braces = true; -} +{ } InterfaceBlock::InterfaceBlock(const InterfaceBlock &other): Statement(other), @@ -333,6 +346,8 @@ InterfaceBlock::InterfaceBlock(const InterfaceBlock &other): members(other.members), instance_name(other.instance_name), array(other.array), + type_declaration(0), + struct_declaration(0), linked_block(0) { } @@ -340,6 +355,8 @@ InterfaceBlock::~InterfaceBlock() { if(linked_block && linked_block->linked_block==this) linked_block->linked_block = 0; + if(struct_declaration && struct_declaration->interface_block==this) + struct_declaration->interface_block = 0; } void InterfaceBlock::visit(NodeVisitor &visitor) diff --git a/source/glsl/syntax.h b/source/glsl/syntax.h index 2c832c14..30acca42 100644 --- a/source/glsl/syntax.h +++ b/source/glsl/syntax.h @@ -48,6 +48,7 @@ struct Operator enum { + INTERNAL_SOURCE = -2, BUILTIN_SOURCE = -1, GENERATED_SOURCE = 0 }; @@ -352,7 +353,11 @@ struct StructDeclaration: TypeDeclaration { Block members; + InterfaceBlock *interface_block; + StructDeclaration(); + StructDeclaration(const StructDeclaration &); + ~StructDeclaration(); virtual StructDeclaration *clone() const { return new StructDeclaration(*this); } virtual void visit(NodeVisitor &); @@ -387,10 +392,14 @@ struct InterfaceBlock: Statement { std::string interface; std::string name; - Block members; + NodePtr members; std::string instance_name; bool array; + /* An interface block's ultimate base type is always a struct. The + immediate type may be either that same struct or an array of it. */ + TypeDeclaration *type_declaration; + StructDeclaration *struct_declaration; InterfaceBlock *linked_block; InterfaceBlock(); diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index fcccb526..b0c6e3d6 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -149,8 +149,13 @@ void DeclarationValidator::visit(InterfaceBlock &iface) if(!iface.instance_name.empty()) check_definition(iface.instance_name, iface); - SetFlag set_anon(anonymous_block, iface.instance_name.empty()); - TraversingVisitor::visit(iface); + if(iface.instance_name.empty() && iface.struct_declaration) + { + // Inject anonymous interface block members into the global scope + const map &iface_vars = iface.struct_declaration->members.variables; + for(map::const_iterator j=iface_vars.begin(); j!=iface_vars.end(); ++j) + check_definition(j->first, *j->second); + } } void DeclarationValidator::visit(FunctionDeclaration &func) @@ -207,6 +212,13 @@ void ReferenceValidator::visit(VariableDeclaration &var) TraversingVisitor::visit(var); } +void ReferenceValidator::visit(InterfaceBlock &iface) +{ + if(!iface.struct_declaration) + error(iface, format("Interface block '%s %s' lacks a struct declaration", iface.interface, iface.name)); + TraversingVisitor::visit(iface); +} + void ReferenceValidator::visit(FunctionDeclaration &func) { if(!func.return_type_declaration) diff --git a/source/glsl/validate.h b/source/glsl/validate.h index 36b702e0..e5b8ed4e 100644 --- a/source/glsl/validate.h +++ b/source/glsl/validate.h @@ -78,6 +78,7 @@ private: virtual void visit(VariableReference &); virtual void visit(InterfaceBlockReference &); virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); }; diff --git a/source/glsl/visitor.cpp b/source/glsl/visitor.cpp index c740d118..ebcedb71 100644 --- a/source/glsl/visitor.cpp +++ b/source/glsl/visitor.cpp @@ -76,7 +76,8 @@ void TraversingVisitor::visit(VariableDeclaration &var) void TraversingVisitor::visit(InterfaceBlock &iface) { - iface.members.visit(*this); + if(iface.members) + iface.members->visit(*this); } void TraversingVisitor::visit(FunctionDeclaration &func) -- 2.43.0