]> git.tdb.fi Git - libs/gl.git/commitdiff
Improve rules for interface blocks
authorMikko Rasa <tdb@tdb.fi>
Thu, 4 Mar 2021 15:52:11 +0000 (17:52 +0200)
committerMikko Rasa <tdb@tdb.fi>
Thu, 4 Mar 2021 15:59:38 +0000 (17:59 +0200)
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
source/glsl/validate.cpp
source/glsl/validate.h
tests/glsl/block_name_conflict.glsl

index 0a469a46e1dd79b07ad73b82d594e41c11fd5749..ad8515a94392568d4823d84bc3595c44dc9945ee 100644 (file)
@@ -157,8 +157,8 @@ void VariableResolver::visit(VariableReference &var)
        else
        {
                const map<string, InterfaceBlock *> &blocks = stage->interface_blocks;
-               map<string, InterfaceBlock *>::const_iterator i = blocks.find(var.name);
-               if(i!=blocks.end() && i->second->instance_name==var.name)
+               map<string, InterfaceBlock *>::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<string, InterfaceBlock *>::iterator i = stage->interface_blocks.find(iface.name);
+               map<string, InterfaceBlock *>::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<string> 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<Block *> set_block(current_block, &stage->content);
@@ -521,10 +521,12 @@ void InterfaceGenerator::visit(VariableReference &var)
        }
 
        const map<string, InterfaceBlock *> &prev_blocks = stage->previous->interface_blocks;
-       map<string, InterfaceBlock *>::const_iterator j = prev_blocks.find(var.name);
-       if(j!=prev_blocks.end() && j->second->interface=="out" && j->second->instance_name==var.name)
+       map<string, InterfaceBlock *>::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<string, InterfaceBlock *> &prev_blocks = stage->previous->interface_blocks;
-                       map<string, InterfaceBlock *>::const_iterator i = prev_blocks.find(iface.name);
-                       if(i!=prev_blocks.end() && i->second->interface=="out" && i->second->name==iface.name)
+                       map<string, InterfaceBlock *>::const_iterator i = prev_blocks.find("out"+iface.name);
+                       if(i!=prev_blocks.end())
                        {
                                iface.linked_block = i->second;
                                i->second->linked_block = &iface;
index 3d2015bde3ffaae7b1d086d5be502b430c3cc5ed..5fd4ebcae76a8d050285fcb17c48336dbfce315b 100644 (file)
@@ -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<string, InterfaceBlock *>::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<InterfaceBlock *>(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);
 }
index f784ea45e9c4d05413f5d59aa34b6ed8155e7b0b..42c74230c4f90637208b4fb9ca42388f82ad123b 100644 (file)
@@ -27,6 +27,7 @@ private:
        typedef std::map<std::string, Statement *> BlockDeclarationMap;
 
        std::map<Block *, BlockDeclarationMap> declarations;
+       std::map<std::string, InterfaceBlock *> 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 &);
index e397b551203feee1c4f16e52577571773b88e26b..fb69e8bbacca680f6ea6a568296b91fd2c76eee0 100644 (file)
@@ -42,6 +42,6 @@ void main()
 <test>:3: Previous definition is here
 <test>:8: Multiple definition of 'Output'
 <test>:3: Previous definition is here
-<test>:26: Multiple definition of 'Output'
+<test>:26: Multiple definition of interface block 'out Output'
 <test>:22: Previous definition is here
 */