From d72d8a9163e342167f35360c807ee9ea5ebacdc2 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 4 Mar 2021 17:52:11 +0200 Subject: [PATCH] Improve rules for interface blocks The GLSL specification says that using the same block name in different interfaces is allowed, so we must separate blocks by interface. --- source/glsl/generate.cpp | 30 +++++++++++++------------ source/glsl/validate.cpp | 34 ++++++++++++++++++++++++----- source/glsl/validate.h | 3 +++ tests/glsl/block_name_conflict.glsl | 2 +- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 0a469a46..ad8515a9 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -157,8 +157,8 @@ void VariableResolver::visit(VariableReference &var) else { const map &blocks = stage->interface_blocks; - map::const_iterator i = blocks.find(var.name); - if(i!=blocks.end() && i->second->instance_name==var.name) + map::const_iterator i = blocks.find("_"+var.name); + if(i!=blocks.end()) { /* The name refers to an interface block with an instance name rather than a variable. Prepare a new syntax tree node accordingly. */ @@ -201,7 +201,7 @@ void VariableResolver::visit(InterfaceBlockReference &iface) iface.declaration = 0; for(Block *block=current_block; block; block=block->parent) { - map::iterator i = stage->interface_blocks.find(iface.name); + map::iterator i = stage->interface_blocks.find("_"+iface.name); if(i!=stage->interface_blocks.end()) { iface.declaration = i->second; @@ -313,11 +313,11 @@ void VariableResolver::visit(VariableDeclaration &var) void VariableResolver::visit(InterfaceBlock &iface) { - /* Block names can't be used for any other identifiers so we can put them - in the same map with instance names. */ - stage->interface_blocks.insert(make_pair(iface.name, &iface)); + /* Block names can be reused in different interfaces. Prefix the name with + the first character of the interface to avoid conflicts. */ + stage->interface_blocks.insert(make_pair(iface.interface+iface.name, &iface)); if(!iface.instance_name.empty()) - stage->interface_blocks.insert(make_pair(iface.instance_name, &iface)); + stage->interface_blocks.insert(make_pair("_"+iface.instance_name, &iface)); SetForScope set_iface(block_interface, iface.interface); TraversingVisitor::visit(iface); @@ -450,7 +450,7 @@ VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration InterfaceBlock *InterfaceGenerator::generate_interface(InterfaceBlock &out_block) { - if(stage->interface_blocks.count(out_block.name)) + if(stage->interface_blocks.count("in"+out_block.name)) return 0; InterfaceBlock *in_block = new InterfaceBlock; @@ -472,9 +472,9 @@ InterfaceBlock *InterfaceGenerator::generate_interface(InterfaceBlock &out_block } iface_target_block->body.insert(iface_insert_point, in_block); - stage->interface_blocks.insert(make_pair(in_block->name, in_block)); + stage->interface_blocks.insert(make_pair("in"+in_block->name, in_block)); if(!in_block->instance_name.empty()) - stage->interface_blocks.insert(make_pair(in_block->instance_name, in_block)); + stage->interface_blocks.insert(make_pair("_"+in_block->instance_name, in_block)); SetFlag set_scope(function_scope, false); SetForScope set_block(current_block, &stage->content); @@ -521,10 +521,12 @@ void InterfaceGenerator::visit(VariableReference &var) } const map &prev_blocks = stage->previous->interface_blocks; - map::const_iterator j = prev_blocks.find(var.name); - if(j!=prev_blocks.end() && j->second->interface=="out" && j->second->instance_name==var.name) + map::const_iterator j = prev_blocks.find("_"+var.name); + if(j!=prev_blocks.end() && j->second->interface=="out") { generate_interface(*j->second); + /* Let VariableResolver convert the variable reference into an interface + block reference. */ return; } @@ -608,8 +610,8 @@ void InterfaceGenerator::visit(InterfaceBlock &iface) if(!iface.linked_block && stage->previous) { const map &prev_blocks = stage->previous->interface_blocks; - map::const_iterator i = prev_blocks.find(iface.name); - if(i!=prev_blocks.end() && i->second->interface=="out" && i->second->name==iface.name) + map::const_iterator i = prev_blocks.find("out"+iface.name); + if(i!=prev_blocks.end()) { iface.linked_block = i->second; i->second->linked_block = &iface; diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index 3d2015bd..5fd4ebca 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -30,6 +30,12 @@ DeclarationValidator::DeclarationValidator(): anonymous_block(false) { } +void DeclarationValidator::multiple_definition(const string &name, Statement &statement, Statement &previous) +{ + error(&statement, format("Multiple definition of %s", name)); + diagnose(&previous, Diagnostic::INFO, "Previous definition is here"); +} + Statement *DeclarationValidator::find_definition(const string &name) { BlockDeclarationMap *decls = &declarations[current_block]; @@ -45,12 +51,13 @@ Statement *DeclarationValidator::find_definition(const string &name) void DeclarationValidator::check_definition(const string &name, Statement &statement) { if(Statement *previous = find_definition(name)) - { - error(&statement, format("Multiple definition of '%s'", name)); - diagnose(previous, Diagnostic::INFO, "Previous definition is here"); - return; - } + multiple_definition(format("'%s'", name), statement, *previous); + else + record_definition(name, statement); +} +void DeclarationValidator::record_definition(const string &name, Statement &statement) +{ declarations[current_block].insert(make_pair(name, &statement)); if(anonymous_block) declarations[current_block->parent].insert(make_pair(name, &statement)); @@ -64,9 +71,24 @@ void DeclarationValidator::visit(VariableDeclaration &var) void DeclarationValidator::visit(InterfaceBlock &iface) { - check_definition(iface.name, iface); + string key = iface.interface+iface.name; + map::const_iterator i = interface_blocks.find(key); + if(i!=interface_blocks.end()) + multiple_definition(format("interface block '%s %s'", iface.interface, iface.name), iface, *i->second); + else + interface_blocks.insert(make_pair(key, &iface)); + + if(Statement *previous = find_definition(iface.name)) + { + if(!dynamic_cast(previous)) + multiple_definition(format("'%s'", iface.name), iface, *previous); + } + else + record_definition(iface.name, iface); + if(!iface.instance_name.empty()) check_definition(iface.instance_name, iface); + SetFlag set_anon(anonymous_block, iface.instance_name.empty()); TraversingVisitor::visit(iface); } diff --git a/source/glsl/validate.h b/source/glsl/validate.h index f784ea45..42c74230 100644 --- a/source/glsl/validate.h +++ b/source/glsl/validate.h @@ -27,6 +27,7 @@ private: typedef std::map BlockDeclarationMap; std::map declarations; + std::map interface_blocks; bool anonymous_block; public: @@ -35,8 +36,10 @@ public: void apply(Stage &s) { stage = &s; s.content.visit(*this); } private: + void multiple_definition(const std::string &, Statement &, Statement &); Statement *find_definition(const std::string &); void check_definition(const std::string &, Statement &); + void record_definition(const std::string &, Statement &); virtual void visit(VariableDeclaration &); virtual void visit(InterfaceBlock &); diff --git a/tests/glsl/block_name_conflict.glsl b/tests/glsl/block_name_conflict.glsl index e397b551..fb69e8bb 100644 --- a/tests/glsl/block_name_conflict.glsl +++ b/tests/glsl/block_name_conflict.glsl @@ -42,6 +42,6 @@ void main() :3: Previous definition is here :8: Multiple definition of 'Output' :3: Previous definition is here -:26: Multiple definition of 'Output' +:26: Multiple definition of interface block 'out Output' :22: Previous definition is here */ -- 2.43.0