From 03b2ea5c9c611cfa5f02afb49ed7e05743e691b4 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 27 Nov 2021 21:25:03 +0200 Subject: [PATCH] Unify handling of variables and interface blocks in the GLSL compiler In SPIR-V interface blocks are just variables with a struct type marked as block. Treating them this way in the AST reduces duplcation a fair bit. --- source/glsl/debug.cpp | 38 +------ source/glsl/debug.h | 2 - source/glsl/finalize.cpp | 145 +++++++++++--------------- source/glsl/finalize.h | 10 +- source/glsl/generate.cpp | 141 ++++++++++--------------- source/glsl/generate.h | 2 - source/glsl/optimize.cpp | 28 +---- source/glsl/optimize.h | 5 - source/glsl/output.cpp | 53 ++++------ source/glsl/output.h | 2 - source/glsl/parser.cpp | 60 ++++++++--- source/glsl/parser.h | 3 +- source/glsl/reflect.cpp | 15 --- source/glsl/reflect.h | 2 - source/glsl/resolve.cpp | 216 +++++++++++++++------------------------ source/glsl/resolve.h | 10 +- source/glsl/spirv.cpp | 77 +++----------- source/glsl/spirv.h | 2 - source/glsl/syntax.cpp | 49 +-------- source/glsl/syntax.h | 46 +-------- source/glsl/validate.cpp | 138 +++++++++---------------- source/glsl/validate.h | 10 +- source/glsl/visitor.cpp | 43 ++++---- source/glsl/visitor.h | 7 +- 24 files changed, 373 insertions(+), 731 deletions(-) diff --git a/source/glsl/debug.cpp b/source/glsl/debug.cpp index ef7e81f6..60b7c247 100644 --- a/source/glsl/debug.cpp +++ b/source/glsl/debug.cpp @@ -183,19 +183,10 @@ void DumpTree::visit(VariableReference &var) string text; if(var.declaration) text += format("%s ", get_label(*var.declaration)); - text += format("%s (var) -> %s", format_name(var.name), format_type(var.type)); + text += format("%s -> %s", format_name(var.name), format_type(var.type)); append(var, text); } -void DumpTree::visit(InterfaceBlockReference &iface) -{ - string text; - if(iface.declaration) - text += format("%s ", get_label(*iface.declaration)); - text += format("%s (iface) -> %s", format_name(iface.name), format_type(iface.type)); - append(iface, text); -} - void DumpTree::visit(MemberAccess &memacc) { string text = "Member access:"; @@ -373,6 +364,8 @@ void DumpTree::visit(StructDeclaration &strct) { append(strct, format("%s struct %s", get_label(strct), strct.name)); vector branches; + if(!strct.block_name.empty()) + branches.emplace_back(format("Interface block: %s", format_name(strct.block_name))); if(strct.extended_alignment) branches.emplace_back("Extended alignment"); branches.emplace_back(&strct.members); @@ -402,6 +395,8 @@ void DumpTree::visit(VariableDeclaration &var) vector branches; if(var.type_declaration) branches.emplace_back(format("Type: %s %s", get_label(*var.type_declaration), format_type(var.type_declaration->name))); + if(var.block_declaration) + branches.emplace_back(format("Interface block: %s", format_name(var.block_declaration->block_name))); if(var.layout) branches.emplace_back(var.layout.get()); if(var.array) @@ -416,29 +411,6 @@ void DumpTree::visit(VariableDeclaration &var) append_subtree(branches); } -void DumpTree::visit(InterfaceBlock &iface) -{ - string head = format("%s %s %s", get_label(iface), iface.interface, format_name(iface.block_name)); - if(!iface.instance_name.empty()) - head += format(" %s", format_name(iface.instance_name)); - if(iface.array) - head += "[]"; - if(iface.source==BUILTIN_SOURCE) - head += " (builtin)"; - else if(iface.linked_block) - head += " (linked)"; - append(iface, head); - - vector branches; - if(iface.type_declaration) - branches.emplace_back(format("Type: %s %s", get_label(*iface.type_declaration), format_type(iface.type_declaration->name))); - if(iface.layout) - branches.emplace_back(iface.layout.get()); - if(iface.members) - branches.emplace_back(iface.members.get()); - append_subtree(branches); -} - void DumpTree::visit(FunctionDeclaration &func) { string text = format("%s %s %s%s", get_label(func), format_type(func.return_type), format_name(func.name), (func.signature.empty() ? "(?)" : func.signature)); diff --git a/source/glsl/debug.h b/source/glsl/debug.h index 5b2a3d96..b3682e7b 100644 --- a/source/glsl/debug.h +++ b/source/glsl/debug.h @@ -76,7 +76,6 @@ private: virtual void visit(Block &); virtual void visit(Literal &); virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); @@ -93,7 +92,6 @@ private: virtual void visit(ImageTypeDeclaration &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); virtual void visit(Conditional &); virtual void visit(Iteration &); diff --git a/source/glsl/finalize.cpp b/source/glsl/finalize.cpp index 52cf9580..5307cff9 100644 --- a/source/glsl/finalize.cpp +++ b/source/glsl/finalize.cpp @@ -72,8 +72,8 @@ void LocationAllocator::apply(Module &module, const Features &f, bool a) if(features.target_api!=VULKAN) allocate_locations("uniform"); - for(InterfaceBlock *b: unbound_blocks) - bind_uniform(b->layout, b->block_name, features.uniform_binding_range); + for(VariableDeclaration *b: unbound_blocks) + bind_uniform(b->layout, b->block_declaration->block_name, features.uniform_binding_range); for(VariableDeclaration *t: unbound_textures) bind_uniform(t->layout, t->name, features.texture_binding_range); } @@ -198,7 +198,7 @@ void LocationAllocator::visit(VariableDeclaration &var) if(!var.name.compare(0, 3, "gl_")) return; - if(!var.interface.empty()) + if(!var.interface.empty() && !var.block_declaration) { int location = get_layout_value(var.layout.get(), "location"); @@ -223,22 +223,18 @@ void LocationAllocator::visit(VariableDeclaration &var) if(var.interface=="uniform") { - const TypeDeclaration *base_type = get_ultimate_base_type(var.type_declaration); - if(dynamic_cast(base_type) && !visit_uniform(var.name, var.layout)) - unbound_textures.push_back(&var); - } -} - -void LocationAllocator::visit(InterfaceBlock &iface) -{ - if(!iface.instance_name.compare(0, 3, "gl_")) - return; - - if(iface.interface=="uniform") - { - bool push_constant = has_layout_qualifier(iface.layout.get(), "push_constant"); - if(!push_constant && !visit_uniform(iface.block_name, iface.layout)) - unbound_blocks.push_back(&iface); + if(var.block_declaration) + { + bool push_constant = has_layout_qualifier(var.layout.get(), "push_constant"); + if(!push_constant && !visit_uniform(var.block_declaration->block_name, var.layout)) + unbound_blocks.push_back(&var); + } + else + { + const TypeDeclaration *base_type = get_ultimate_base_type(var.type_declaration); + if(dynamic_cast(base_type) && !visit_uniform(var.name, var.layout)) + unbound_textures.push_back(&var); + } } } @@ -413,11 +409,8 @@ void StructuralFeatureConverter::visit(VariableReference &var) var.name = "gl_FragColor"; var.declaration = 0; } -} -void StructuralFeatureConverter::visit(InterfaceBlockReference &iface) -{ - r_flattened_interface = nodes_to_remove.count(iface.declaration); + r_flattened_interface = nodes_to_remove.count(var.declaration); } void StructuralFeatureConverter::visit(MemberAccess &memacc) @@ -486,18 +479,6 @@ void StructuralFeatureConverter::visit(FunctionCall &call) TraversingVisitor::visit(call); } -void StructuralFeatureConverter::visit(VariableDeclaration &var) -{ - if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax()) - if(stage->type==Stage::FRAGMENT && var.interface=="out") - { - frag_out = &var; - nodes_to_remove.insert(&var); - } - - TraversingVisitor::visit(var); -} - bool StructuralFeatureConverter::supports_interface_blocks(const string &iface) const { if(features.target_api==VULKAN) @@ -517,27 +498,35 @@ bool StructuralFeatureConverter::supports_interface_blocks(const string &iface) return false; } -void StructuralFeatureConverter::visit(InterfaceBlock &iface) +void StructuralFeatureConverter::visit(VariableDeclaration &var) { - bool push_constant = has_layout_qualifier(iface.layout.get(), "push_constant"); - if((!supports_interface_blocks(iface.interface) || (push_constant && features.target_api!=VULKAN)) && iface.type_declaration) + if(var.block_declaration) { - if(!iface.instance_name.empty()) - unsupported("ARB_uniform_buffer_object required for interface block instances"); - else if(iface.struct_declaration) + bool push_constant = has_layout_qualifier(var.layout.get(), "push_constant"); + if(!supports_interface_blocks(var.interface) || (push_constant && features.target_api!=VULKAN)) { - for(const RefPtr &s: iface.struct_declaration->members.body) - if(VariableDeclaration *var = dynamic_cast(s.get())) - var->interface = iface.interface; - stage->content.body.splice(uniform_insert_point, iface.struct_declaration->members.body); - nodes_to_remove.insert(&iface); - nodes_to_remove.insert(iface.struct_declaration); + if(var.name.find(' ')==string::npos) + unsupported("ARB_uniform_buffer_object required for interface block instances"); + else + { + for(const RefPtr &s: var.block_declaration->members.body) + if(VariableDeclaration *mem = dynamic_cast(s.get())) + mem->interface = var.interface; + stage->content.body.splice(uniform_insert_point, var.block_declaration->members.body); + nodes_to_remove.insert(&var); + nodes_to_remove.insert(var.block_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"); } + + if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax()) + if(stage->type==Stage::FRAGMENT && var.interface=="out") + { + frag_out = &var; + nodes_to_remove.insert(&var); + } + + TraversingVisitor::visit(var); } @@ -618,6 +607,18 @@ bool QualifierConverter::supports_binding() const return check_version(Version(4, 20)); } +bool QualifierConverter::supports_interface_block_location() const +{ + if(features.target_api==VULKAN) + return true; + else if(features.target_api==OPENGL_ES) + return check_version(Version(3, 20)); + else if(check_version(Version(4, 40))) + return true; + else + return check_extension(&Features::arb_enhanced_layouts); +} + void QualifierConverter::visit(VariableDeclaration &var) { if(var.layout) @@ -628,7 +629,9 @@ void QualifierConverter::visit(VariableDeclaration &var) { bool supported = true; bool external = false; - if(var.interface=="in") + if(var.block_declaration) + supported = supports_interface_block_location(); + else if(var.interface=="in") { external = (stage->type==Stage::VERTEX); supported = (external ? supports_interface_layouts() : supports_stage_interface_layouts()); @@ -658,7 +661,9 @@ void QualifierConverter::visit(VariableDeclaration &var) } else if(i->name=="binding" && !supports_binding()) { - if(dynamic_cast(get_ultimate_base_type(var.type_declaration))) + if(var.block_declaration) + stage->uniform_block_bindings[var.block_declaration->block_name] = i->value; + else if(dynamic_cast(get_ultimate_base_type(var.type_declaration))) stage->texture_bindings[var.name] = i->value; i = var.layout->qualifiers.erase(i); @@ -689,40 +694,6 @@ void QualifierConverter::visit(VariableDeclaration &var) TraversingVisitor::visit(var); } -bool QualifierConverter::supports_interface_block_location() const -{ - if(features.target_api==VULKAN) - return true; - else if(features.target_api==OPENGL_ES) - return check_version(Version(3, 20)); - else if(check_version(Version(4, 40))) - return true; - else - return check_extension(&Features::arb_enhanced_layouts); -} - -void QualifierConverter::visit(InterfaceBlock &iface) -{ - if(iface.layout) - { - for(auto i=iface.layout->qualifiers.begin(); i!=iface.layout->qualifiers.end(); ) - { - if(i->name=="location" && !supports_interface_block_location()) - i = iface.layout->qualifiers.erase(i); - else if(i->name=="binding" && !supports_binding()) - { - stage->uniform_block_bindings[iface.block_name] = i->value; - i = iface.layout->qualifiers.erase(i); - } - else - ++i; - } - - if(iface.layout->qualifiers.empty()) - iface.layout = 0; - } -} - } // namespace SL } // namespace GL } // namespace Msp diff --git a/source/glsl/finalize.h b/source/glsl/finalize.h index f9502954..79ba54b8 100644 --- a/source/glsl/finalize.h +++ b/source/glsl/finalize.h @@ -41,7 +41,7 @@ private: std::map > used_bindings; std::vector unplaced_variables; std::vector unbound_textures; - std::vector unbound_blocks; + std::vector unbound_blocks; public: void apply(Module &, const Features &, bool = true); @@ -53,7 +53,6 @@ private: bool visit_uniform(const std::string &, RefPtr &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &) { } }; @@ -117,14 +116,12 @@ private: bool supports_stage(Stage::Type) const; bool supports_unified_interface_syntax() const; virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); virtual void visit(Assignment &); bool supports_unified_sampling_functions() const; virtual void visit(FunctionCall &); - virtual void visit(VariableDeclaration &); bool supports_interface_blocks(const std::string &) const; - virtual void visit(InterfaceBlock &); + virtual void visit(VariableDeclaration &); }; /** Converts qualifiers on variables and blocksto match a particular set of @@ -142,9 +139,8 @@ private: bool supports_sample_sampling() const; bool supports_uniform_location() const; bool supports_binding() const; - virtual void visit(VariableDeclaration &); bool supports_interface_block_location() const; - virtual void visit(InterfaceBlock &); + virtual void visit(VariableDeclaration &); }; } // namespace SL diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 3175c6c9..0a9e8e85 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -100,7 +100,7 @@ VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration if(stage->content.variables.count(name)) return 0; - if(stage->type==Stage::GEOMETRY && !copy_block && var.interface=="out" && var.array) + if(stage->type==Stage::GEOMETRY && var.interface=="out" && var.array) return 0; VariableDeclaration* iface_var = new VariableDeclaration; @@ -108,9 +108,8 @@ VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration iface_var->interface = iface; iface_var->type = var.type; iface_var->name = name; - /* Geometry shader inputs are always arrays. But if we're bringing in an - entire block, the array is on the block and not individual variables. */ - if(stage->type==Stage::GEOMETRY && !copy_block) + // Geometry shader inputs are always arrays. + if(stage->type==Stage::GEOMETRY) iface_var->array = ((var.array && var.interface!="in") || iface=="in"); else iface_var->array = var.array; @@ -123,6 +122,21 @@ VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration var.linked_declaration = iface_var; } + if(var.block_declaration) + { + StructDeclaration *iface_type = var.block_declaration->clone(); + iface_type->name = format("_%s_%s", iface, var.block_declaration->block_name); + iface_target_block->body.insert(iface_insert_point, iface_type); + + iface_var->type = iface_type->name; + if(name.empty()) + iface_var->name = format("%s %s", iface, var.block_declaration->block_name); + + stage->interface_blocks.insert(make_pair("in "+var.block_declaration->block_name, iface_var)); + if(!name.empty()) + stage->interface_blocks.insert(make_pair(name, iface_var)); + } + iface_target_block->body.insert(iface_insert_point, iface_var); iface_target_block->variables.insert(make_pair(name, iface_var)); if(iface_target_block==&stage->content && iface=="in") @@ -131,51 +145,26 @@ VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration return iface_var; } -InterfaceBlock *InterfaceGenerator::generate_interface(InterfaceBlock &out_block) +ExpressionStatement &InterfaceGenerator::insert_assignment(const string &left, Expression *right) { - if(stage->interface_blocks.count("in "+out_block.block_name)) - return 0; + Assignment *assign = new Assignment; - InterfaceBlock *in_block = new InterfaceBlock; - in_block->interface = "in"; - in_block->block_name = out_block.block_name; - in_block->members = new Block; - in_block->instance_name = out_block.instance_name; - if(stage->type==Stage::GEOMETRY) - in_block->array = true; - else - in_block->array = out_block.array; - in_block->linked_block = &out_block; - out_block.linked_block = in_block; + string::size_type dot = left.find('.'); + VariableReference *ref = new VariableReference; + ref->name = left.substr(0, dot); + assign->left = ref; + while(dot!=string::npos) { - SetFlag set_copy(copy_block, true); - 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); - stage->interface_blocks.insert(make_pair("in "+in_block->block_name, in_block)); - if(!in_block->instance_name.empty()) - stage->interface_blocks.insert(make_pair(in_block->instance_name, in_block)); + string::size_type start = dot+1; + dot = left.find('.', start); - SetFlag set_scope(function_scope, false); - SetForScope set_block(current_block, &stage->content); - in_block->visit(*this); - - return in_block; -} + MemberAccess *memacc = new MemberAccess; + memacc->left = assign->left; + memacc->member = left.substr(start, dot-start); + assign->left = memacc; + } -ExpressionStatement &InterfaceGenerator::insert_assignment(const string &left, Expression *right) -{ - Assignment *assign = new Assignment; - VariableReference *ref = new VariableReference; - ref->name = left; - assign->left = ref; assign->oper = &Operator::get_operator("=", Operator::BINARY); assign->right = right; @@ -213,24 +202,14 @@ void InterfaceGenerator::visit(VariableReference &var) return; } - const map &prev_blocks = stage->previous->interface_blocks; - auto 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; - } - - for(const auto &kvp: prev_blocks) - if(kvp.second->instance_name.empty() && kvp.second->struct_declaration) + for(const auto &kvp: stage->previous->interface_blocks) + if(kvp.first.find(' ')!=string::npos) { - const map &iface_vars = kvp.second->struct_declaration->members.variables; + const map &iface_vars = kvp.second->block_declaration->members.variables; i = iface_vars.find(var.name); if(i!=iface_vars.end()) { - generate_interface(*kvp.second); + generate_interface(*kvp.second, "in", string()); return; } } @@ -238,9 +217,7 @@ void InterfaceGenerator::visit(VariableReference &var) void InterfaceGenerator::visit(VariableDeclaration &var) { - if(copy_block) - generate_interface(var, "in", var.name); - else if(var.interface=="out") + if(var.interface=="out") { /* For output variables in function scope, generate a global interface and replace the local declaration with an assignment. */ @@ -268,38 +245,30 @@ void InterfaceGenerator::visit(VariableDeclaration &var) previous stage. */ if(!var.linked_declaration && stage->previous) { - const map &prev_vars = stage->previous->content.variables; - auto i = prev_vars.find(var.name); - if(i!=prev_vars.end() && i->second->interface=="out") + const map *prev_vars; + string name; + // Blocks are linked by their block name, not instance name + if(var.block_declaration) { - var.linked_declaration = i->second; - i->second->linked_declaration = &var; + prev_vars = &stage->previous->interface_blocks; + name = "out "+var.block_declaration->block_name; + } + else + { + prev_vars = &stage->previous->content.variables; + name = var.name; } - } - } - - TraversingVisitor::visit(var); -} -void InterfaceGenerator::visit(InterfaceBlock &iface) -{ - if(iface.interface=="in") - { - /* Try to link input blocks with output blocks sharing the same block - name from previous stage. */ - if(!iface.linked_block && stage->previous) - { - const map &prev_blocks = stage->previous->interface_blocks; - auto i = prev_blocks.find("out "+iface.block_name); - if(i!=prev_blocks.end()) + auto i = prev_vars->find(name); + if(i!=prev_vars->end() && i->second->interface=="out") { - iface.linked_block = i->second; - i->second->linked_block = &iface; + var.linked_declaration = i->second; + i->second->linked_declaration = &var; } } } - TraversingVisitor::visit(iface); + TraversingVisitor::visit(var); } void InterfaceGenerator::visit(FunctionDeclaration &func) @@ -332,7 +301,7 @@ void InterfaceGenerator::visit(Passthrough &pass) { /* Special case for geometry shader: copy gl_Position from input to output. */ - InterfaceBlockReference *ref = new InterfaceBlockReference; + VariableReference *ref = new VariableReference; ref->name = "gl_in"; BinaryExpression *subscript = new BinaryExpression; @@ -344,7 +313,7 @@ void InterfaceGenerator::visit(Passthrough &pass) memacc->left = subscript; memacc->member = "gl_Position"; - insert_assignment("gl_Position", memacc); + insert_assignment("out gl_PerVertex.gl_Position", memacc); } for(VariableDeclaration *v: pass_vars) diff --git a/source/glsl/generate.h b/source/glsl/generate.h index d828daa5..73b933bf 100644 --- a/source/glsl/generate.h +++ b/source/glsl/generate.h @@ -56,11 +56,9 @@ private: std::string change_prefix(const std::string &, const std::string &) const; virtual void visit(Block &); VariableDeclaration *generate_interface(VariableDeclaration &, const std::string &, const std::string &); - InterfaceBlock *generate_interface(InterfaceBlock &); ExpressionStatement &insert_assignment(const std::string &, Expression *); virtual void visit(VariableReference &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); virtual void visit(Passthrough &); }; diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index da951589..1b9b41de 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -191,12 +191,6 @@ void InlineContentInjector::visit(VariableReference &var) referenced_names.insert(var.name); } -void InlineContentInjector::visit(InterfaceBlockReference &iface) -{ - if(pass==REFERENCED) - referenced_names.insert(iface.name); -} - void InlineContentInjector::visit(FunctionCall &call) { if(pass==REFERENCED) @@ -1246,11 +1240,6 @@ void UnusedTypeRemover::visit(VariableDeclaration &var) TraversingVisitor::visit(var); } -void UnusedTypeRemover::visit(InterfaceBlock &iface) -{ - unused_nodes.erase(iface.type_declaration); -} - void UnusedTypeRemover::visit(FunctionDeclaration &func) { unused_nodes.erase(func.return_type_declaration); @@ -1313,14 +1302,6 @@ void UnusedVariableRemover::visit(VariableReference &var) referenced(var.declaration, var); } -void UnusedVariableRemover::visit(InterfaceBlockReference &iface) -{ - if(composite_reference) - r_reference.declaration = iface.declaration; - else if(iface.declaration) - referenced(iface.declaration, iface); -} - void UnusedVariableRemover::visit_composite(Expression &expr) { if(!composite_reference) @@ -1474,7 +1455,8 @@ void UnusedVariableRemover::visit(VariableDeclaration &var) /* Mark variables as output if they're used by the next stage or the graphics API. */ - var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_"))); + bool builtin = (!var.name.compare(0, 3, "gl_") || (var.block_declaration && !var.block_declaration->block_name.compare(0, 3, "gl_"))); + var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || builtin)); // Linked outputs are automatically referenced. if(var_info.output && var.linked_declaration) @@ -1487,12 +1469,6 @@ void UnusedVariableRemover::visit(VariableDeclaration &var) } } -void UnusedVariableRemover::visit(InterfaceBlock &iface) -{ - VariableInfo &var_info = variables[&iface]; - var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.block_name.compare(0, 3, "gl_"))); -} - void UnusedVariableRemover::merge_variables(const BlockVariableMap &other_vars) { for(const auto &kvp: other_vars) diff --git a/source/glsl/optimize.h b/source/glsl/optimize.h index 75fffa13..33998e5e 100644 --- a/source/glsl/optimize.h +++ b/source/glsl/optimize.h @@ -71,7 +71,6 @@ public: private: virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(FunctionCall &); virtual void visit(VariableDeclaration &); virtual void visit(Return &); @@ -195,7 +194,6 @@ private: virtual void visit(BinaryExpression &); virtual void visit(StructDeclaration &) { } virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &) { } virtual void visit(FunctionDeclaration &); }; @@ -311,7 +309,6 @@ private: virtual void visit(ImageTypeDeclaration &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); }; @@ -357,7 +354,6 @@ public: private: void referenced(const Assignment::Target &, Node &); virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); void visit_composite(Expression &); virtual void visit(MemberAccess &); virtual void visit(Swizzle &); @@ -370,7 +366,6 @@ private: virtual void visit(ExpressionStatement &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); void merge_variables(const BlockVariableMap &); virtual void visit(FunctionDeclaration &); virtual void visit(Conditional &); diff --git a/source/glsl/output.cpp b/source/glsl/output.cpp index 6b761674..07da64e3 100644 --- a/source/glsl/output.cpp +++ b/source/glsl/output.cpp @@ -144,15 +144,9 @@ void Formatter::visit(Literal &literal) void Formatter::visit(VariableReference &var) { - append(var.name); - r_empty_name = false; -} - -void Formatter::visit(InterfaceBlockReference &iface) -{ - r_empty_name = iface.declaration->instance_name.empty(); + r_empty_name = var.name.find(' ')!=string::npos; if(!r_empty_name) - append(iface.declaration->instance_name); + append(var.name); } void Formatter::visit(MemberAccess &memacc) @@ -255,6 +249,9 @@ void Formatter::visit(InterfaceLayout &layout) void Formatter::visit(StructDeclaration &strct) { + if(!strct.block_name.empty()) + return; + append(format("struct %s\n", strct.name)); strct.members.visit(*this); append(';'); @@ -287,10 +284,22 @@ void Formatter::visit(VariableDeclaration &var) } if(!var.precision.empty()) append(format("%s ", var.precision)); - string type_name = var.type_declaration->name; - if(var.array) - type_name = type_name.substr(0, type_name.find('[')); - append(format("%s %s", type_name, var.name)); + + if(var.block_declaration) + { + append(format("%s\n", var.block_declaration->block_name)); + var.block_declaration->members.visit(*this); + if(var.name.find(' ')==string::npos) + append(format(" %s", var.name)); + } + else + { + string type_name = var.type_declaration->name; + if(var.array) + type_name = type_name.substr(0, type_name.find('[')); + append(format("%s %s", type_name, var.name)); + } + if(var.array) { append('['); @@ -307,26 +316,6 @@ void Formatter::visit(VariableDeclaration &var) append(';'); } -void Formatter::visit(InterfaceBlock &iface) -{ - if(iface.layout) - { - iface.layout->visit(*this); - append(' '); - } - append(format("%s %s\n", iface.interface, iface.block_name)); - if(iface.struct_declaration) - iface.struct_declaration->members.visit(*this); - if(!iface.instance_name.empty()) - { - append(' '); - append(iface.instance_name); - if(iface.array) - append("[]"); - } - append(';'); -} - void Formatter::visit(FunctionDeclaration &func) { append(format("%s %s(", func.return_type_declaration->name, func.name)); diff --git a/source/glsl/output.h b/source/glsl/output.h index dbdd888e..ec794912 100644 --- a/source/glsl/output.h +++ b/source/glsl/output.h @@ -34,7 +34,6 @@ private: void visit_expression(Expression &, const Operator *, bool); virtual void visit(Literal &); virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); @@ -49,7 +48,6 @@ private: virtual void visit(InterfaceLayout &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); virtual void visit(Conditional &); virtual void visit(Iteration &); diff --git a/source/glsl/parser.cpp b/source/glsl/parser.cpp index 46bee183..8c10c443 100644 --- a/source/glsl/parser.cpp +++ b/source/glsl/parser.cpp @@ -66,7 +66,14 @@ void Parser::parse_source(const string &name, int index) allow_stage_change = true; while(!tokenizer.peek_token().empty()) if(RefPtr statement = parse_with_recovery(&Parser::parse_global_declaration)) + { cur_stage->content.body.push_back(statement); + if(next_global_declaration) + { + cur_stage->content.body.push_back(next_global_declaration); + next_global_declaration = 0; + } + } if(!errors.empty()) throw invalid_shader_source(join(errors.begin(), errors.end(), "\n")); @@ -99,6 +106,11 @@ void Parser::stage_change(Stage::Type stage) cur_stage = &module->stages.back(); stage_types.clear(); + if(const Stage *builtin = get_builtins(stage)) + { + for(const auto &kvp: builtin->types) + stage_types.insert(kvp.first); + } for(const Module *m: imported_modules) { auto j = find_member(m->stages, stage, &Stage::type); @@ -275,9 +287,11 @@ RefPtr Parser::parse_global_declaration() } else if(is_interface_qualifier(token) && tokenizer.peek_token(2)=="{") { - RefPtr iface = parse_interface_block(); - iface->layout = layout; - return iface; + RefPtr iface_strct = parse_interface_block(); + VariableDeclaration *iface_var = iface_strct->block_declaration; + iface_var->layout = layout; + next_global_declaration = iface_var; + return iface_strct; } else { @@ -296,7 +310,11 @@ RefPtr Parser::parse_global_declaration() if(is_type(next) || is_qualifier(next)) return parse_variable_declaration(); else - return parse_interface_block(); + { + RefPtr iface_strct = parse_interface_block(); + next_global_declaration = iface_strct->block_declaration; + return iface_strct; + } } else if(is_qualifier(token)) return parse_variable_declaration(); @@ -811,29 +829,39 @@ RefPtr Parser::parse_function_declaration() return func; } -RefPtr Parser::parse_interface_block() +RefPtr Parser::parse_interface_block() { - RefPtr iface = create_node(); - - iface->interface = tokenizer.parse_token(); - if(!is_interface_qualifier(iface->interface)) - throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier"); + RefPtr strct = create_node(); + RefPtr var = create_node(); - iface->block_name = expect_identifier(); - iface->members = new Block; - parse_block(*iface->members, true, &Parser::parse_variable_declaration_with_layout); + var->interface = tokenizer.parse_token(); + if(!is_interface_qualifier(var->interface)) + throw parse_error(tokenizer.get_location(), var->interface, "an interface qualifier"); + + strct->block_name = expect_identifier(); + string name_base = format("_%s_%s", var->interface, strct->block_name); + strct->name = name_base; + for(unsigned i=1; (stage_types.count(strct->name) || global_types.count(strct->name)); ++i) + strct->name = format("%s_%d", name_base, i); + var->type = strct->name; + parse_block(strct->members, true, &Parser::parse_variable_declaration_with_layout); if(!check(";")) { - iface->instance_name = expect_identifier(); + var->name = expect_identifier(); if(check("[")) { - iface->array = true; + var->array = true; tokenizer.expect("]"); } tokenizer.expect(";"); } + else + var->name = format("%s %s", var->interface, strct->block_name); + + strct->block_declaration = var.release(); + add_type(*strct); - return iface; + return strct; } RefPtr Parser::parse_conditional() diff --git a/source/glsl/parser.h b/source/glsl/parser.h index b35b8bbe..51616378 100644 --- a/source/glsl/parser.h +++ b/source/glsl/parser.h @@ -30,6 +30,7 @@ private: std::set global_types; std::set stage_types; std::vector errors; + RefPtr next_global_declaration; public: Parser(ModuleCache *); @@ -87,7 +88,7 @@ private: RefPtr parse_variable_declaration(); RefPtr parse_variable_declaration_with_layout(); RefPtr parse_function_declaration(); - RefPtr parse_interface_block(); + RefPtr parse_interface_block(); RefPtr parse_conditional(); RefPtr parse_for(); RefPtr parse_while(); diff --git a/source/glsl/reflect.cpp b/source/glsl/reflect.cpp index 21f12d0e..643c42e7 100644 --- a/source/glsl/reflect.cpp +++ b/source/glsl/reflect.cpp @@ -348,15 +348,6 @@ void DependencyCollector::visit(VariableReference &var) } } -void DependencyCollector::visit(InterfaceBlockReference &iface) -{ - if(iface.declaration) - { - dependencies.insert(iface.declaration); - iface.declaration->visit(*this); - } -} - void DependencyCollector::visit(FunctionCall &call) { if(call.declaration) @@ -402,12 +393,6 @@ void AssignmentCollector::visit(VariableReference &var) assigned_variables.insert(var.declaration); } -void AssignmentCollector::visit(InterfaceBlockReference &iface) -{ - if(assignment_target) - assigned_variables.insert(iface.declaration); -} - void AssignmentCollector::visit(UnaryExpression &unary) { SetFlag set_assignment(assignment_target, (unary.oper->token[1]=='+' || unary.oper->token[1]=='-')); diff --git a/source/glsl/reflect.h b/source/glsl/reflect.h index 7c4d26c4..6e6f9d83 100644 --- a/source/glsl/reflect.h +++ b/source/glsl/reflect.h @@ -98,7 +98,6 @@ public: private: virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(FunctionCall &); virtual void visit(VariableDeclaration &); virtual void visit(FunctionDeclaration &); @@ -115,7 +114,6 @@ public: private: virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); diff --git a/source/glsl/resolve.cpp b/source/glsl/resolve.cpp index 2f3192d7..3aeab30b 100644 --- a/source/glsl/resolve.cpp +++ b/source/glsl/resolve.cpp @@ -105,13 +105,32 @@ void TypeResolver::visit(ImageTypeDeclaration &type) void TypeResolver::visit(StructDeclaration &strct) { stage->types.insert(make_pair(strct.name, &strct)); - SetForScope set_iface(iface_block, strct.interface_block); - TraversingVisitor::visit(strct); + if(strct.block_name.empty()) + { + SetForScope set_iface(iface_block, strct.block_declaration); + TraversingVisitor::visit(strct); + } + else + block_member_type_ins_pt = type_insert_point; } void TypeResolver::visit(VariableDeclaration &var) { resolve_type(var.type_declaration, var.type, var.array); + + var.block_declaration = 0; + if(StructDeclaration *strct = dynamic_cast(get_ultimate_base_type(var.type_declaration))) + if(!strct->block_name.empty()) + { + var.block_declaration = strct; + strct->block_declaration = &var; + strct->extended_alignment = true; + + SetForScope::iterator> set_ins_pt(type_insert_point, block_member_type_ins_pt); + SetForScope set_iface(iface_block, &var); + TraversingVisitor::visit(*strct); + } + if(iface_block) { if(var.interface==iface_block->interface) @@ -121,33 +140,6 @@ void TypeResolver::visit(VariableDeclaration &var) } } -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.block_name); - strct->members.body.splice(strct->members.body.begin(), iface.members->body); - strct->extended_alignment = true; - 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) { resolve_type(func.return_type_declaration, func.return_type, false); @@ -222,30 +214,16 @@ void VariableResolver::visit(VariableReference &var) if(!declaration) { - const map &blocks = stage->interface_blocks; - auto i = blocks.find(var.name); - if(i==blocks.end()) - { - // Look for the variable in anonymous interface blocks. - for(i=blocks.begin(); i!=blocks.end(); ++i) - if(i->second->instance_name.empty() && i->second->struct_declaration) - if(i->second->struct_declaration->members.variables.count(var.name)) - break; - } - - if(i!=blocks.end()) - { - /* The name refers to either an interface block with an instance name - or a variable declared inside an anonymous interface block. Prepare - new syntax tree nodes accordingly. */ - InterfaceBlockReference *iface_ref = new InterfaceBlockReference; - iface_ref->source = var.source; - iface_ref->line = var.line; - iface_ref->declaration = i->second; - - if(i->second->instance_name.empty()) + for(const auto &kvp: stage->interface_blocks) + if(kvp.second->name.find(' ')!=string::npos && kvp.second->block_declaration->members.variables.count(var.name)) { - iface_ref->name = format("%s %s", i->second->interface, i->second->block_name); + /* The name refers a member of an anonymous interface block. Prepare + new syntax tree nodes accordingly. */ + VariableReference *iface_ref = new VariableReference; + iface_ref->name = kvp.first; + iface_ref->source = var.source; + iface_ref->line = var.line; + iface_ref->declaration = kvp.second; MemberAccess *memacc = new MemberAccess; memacc->source = var.source; @@ -254,13 +232,8 @@ void VariableResolver::visit(VariableReference &var) memacc->member = var.name; r_replacement_expr = memacc; + break; } - else - { - iface_ref->name = var.name; - r_replacement_expr = iface_ref; - } - } } r_any_resolved |= (declaration!=var.declaration); @@ -269,16 +242,6 @@ void VariableResolver::visit(VariableReference &var) check_assignment_target(var.declaration); } -void VariableResolver::visit(InterfaceBlockReference &iface) -{ - auto i = stage->interface_blocks.find(iface.name); - InterfaceBlock *declaration = (i!=stage->interface_blocks.end() ? i->second : 0); - r_any_resolved |= (declaration!=iface.declaration); - iface.declaration = declaration; - - check_assignment_target(iface.declaration); -} - void VariableResolver::visit(MemberAccess &memacc) { TraversingVisitor::visit(memacc); @@ -421,20 +384,20 @@ void VariableResolver::visit(VariableDeclaration &var) auto i = current_block->variables.find(var.name); VariableDeclaration *existing = 0; - InterfaceBlock *block = 0; + VariableDeclaration *block = 0; if(i!=current_block->variables.end()) existing = i->second; else if(!current_block->parent) { - const map &blocks = stage->interface_blocks; + const map &blocks = stage->interface_blocks; for(auto j=blocks.begin(); j!=blocks.end(); ++j) - if(j->second->instance_name.empty() && j->second->struct_declaration) + if(j->second->name.find(' ')!=string::npos) { - map &block_vars = j->second->struct_declaration->members.variables; - i = block_vars.find(var.name); - if(i!=block_vars.end()) + const map &block_vars = j->second->block_declaration->members.variables; + auto k = block_vars.find(var.name); + if(k!=block_vars.end()) { - existing = i->second; + existing = k->second; block = j->second; break; } @@ -442,24 +405,60 @@ void VariableResolver::visit(VariableDeclaration &var) } if(!existing) + { current_block->variables.insert(make_pair(var.name, &var)); - else if(!current_block->parent && (block ? block->interface : existing->interface)==var.interface && existing->type==var.type && existing->array==var.array) + if(var.block_declaration) + { + stage->interface_blocks.insert(make_pair(format("%s %s", var.interface, var.block_declaration->block_name), &var)); + if(var.name.find(' ')==string::npos) + stage->interface_blocks.insert(make_pair(var.name, &var)); + } + } + else if(!current_block->parent && (block ? block->interface : existing->interface)==var.interface && existing->array==var.array) { if(existing->source==BUILTIN_SOURCE) { - redeclare_builtin(*existing, var); - - if(block) + if(var.block_declaration && existing->block_declaration && var.block_declaration->block_name==existing->block_declaration->block_name) { - redeclared_builtins.push_back(block); - for(const auto &kvp: block->struct_declaration->members.variables) - redeclared_builtins.push_back(kvp.second); + const map &vars = var.block_declaration->members.variables; + const map &existing_vars = existing->block_declaration->members.variables; + + bool found_all = true; + for(const auto &kvp: vars) + { + auto j = existing_vars.find(kvp.first); + if(j!=existing_vars.end() && j->second->type==kvp.second->type && j->second->array==kvp.second->array) + redeclare_builtin(*j->second, *kvp.second); + else + found_all = false; + } + + if(found_all) + { + redeclared_builtins.push_back(existing); + nodes_to_remove.insert(&var); + // The block struct will be removed during unused type removal + //nodes_to_remove.insert(var.block_declaration); + } } + else if(!var.block_declaration && !existing->block_declaration && var.type==existing->type) + { + redeclare_builtin(*existing, var); - nodes_to_remove.insert(&var); - r_any_resolved = true; + if(block) + { + /* Cause the block and its members to be marked as not builtin + so it will be emitted in output */ + redeclared_builtins.push_back(block); + for(const auto &kvp: block->block_declaration->members.variables) + redeclared_builtins.push_back(kvp.second); + } + + nodes_to_remove.insert(&var); + r_any_resolved = true; + } } - else if(existing->array && !existing->array_size && !var.layout && !var.init_expression) + else if(existing->array && !existing->array_size && var.type==existing->type && !var.layout && !var.init_expression) { existing->array_size = var.array_size; nodes_to_remove.insert(&var); @@ -468,47 +467,6 @@ void VariableResolver::visit(VariableDeclaration &var) } } -void VariableResolver::visit(InterfaceBlock &iface) -{ - string key = format("%s %s", iface.interface, iface.block_name); - auto i = stage->interface_blocks.find(key); - if(i!=stage->interface_blocks.end()) - { - if(i->second->source==BUILTIN_SOURCE && iface.struct_declaration && i->second->struct_declaration) - { - const map &vars = iface.struct_declaration->members.variables; - const map &existing_vars = i->second->struct_declaration->members.variables; - - bool found_all = true; - for(const auto &kvp: vars) - { - auto j = existing_vars.find(kvp.first); - if(j!=existing_vars.end() && j->second->type==kvp.second->type && j->second->array==kvp.second->array) - redeclare_builtin(*j->second, *kvp.second); - else - found_all = false; - } - - if(found_all) - { - redeclared_builtins.push_back(i->second); - nodes_to_remove.insert(&iface); - nodes_to_remove.insert(iface.struct_declaration); - } - } - } - else - { - /* Block names can be reused in different interfaces. Prepend the interface - to the name to avoid conflicts. */ - stage->interface_blocks.insert(make_pair(key, &iface)); - if(!iface.instance_name.empty()) - stage->interface_blocks.insert(make_pair(iface.instance_name, &iface)); - } - - TraversingVisitor::visit(iface); -} - bool ExpressionResolver::apply(Stage &s) { @@ -630,12 +588,6 @@ void ExpressionResolver::visit(VariableReference &var) resolve(var, var.declaration->type_declaration, true); } -void ExpressionResolver::visit(InterfaceBlockReference &iface) -{ - if(iface.declaration) - resolve(iface, iface.declaration->type_declaration, true); -} - void ExpressionResolver::visit(MemberAccess &memacc) { TraversingVisitor::visit(memacc); diff --git a/source/glsl/resolve.h b/source/glsl/resolve.h index 92a7c336..36af5457 100644 --- a/source/glsl/resolve.h +++ b/source/glsl/resolve.h @@ -32,7 +32,8 @@ private: std::map alias_map; std::map, TypeDeclaration *> array_types; NodeList::iterator type_insert_point; - InterfaceBlock *iface_block = 0; + NodeList::iterator block_member_type_ins_pt; + VariableDeclaration *iface_block = 0; bool r_any_resolved = false; public: @@ -46,12 +47,10 @@ private: virtual void visit(ImageTypeDeclaration &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); }; -/** Resolves variable references. Variable references which match the name -of an interface block are turned into interface block references. */ +/** Resolves variable references. */ class VariableResolver: private TraversingVisitor { private: @@ -72,7 +71,6 @@ private: virtual void visit(RefPtr &); void check_assignment_target(Statement *); virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); virtual void visit(Swizzle &); virtual void visit(BinaryExpression &); @@ -80,7 +78,6 @@ private: void merge_layouts(Layout &, const Layout &); void redeclare_builtin(VariableDeclaration &, VariableDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); }; /** Resolves types and lvalueness of expressions. */ @@ -122,7 +119,6 @@ private: virtual void visit(Block &); virtual void visit(Literal &); virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(MemberAccess &); virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); diff --git a/source/glsl/spirv.cpp b/source/glsl/spirv.cpp index 481f38fb..4828a00c 100644 --- a/source/glsl/spirv.cpp +++ b/source/glsl/spirv.cpp @@ -541,16 +541,6 @@ void SpirVGenerator::visit(VariableReference &var) r_expression_result_id = get_load_id(*var.declaration); } -void SpirVGenerator::visit(InterfaceBlockReference &iface) -{ - if(!composite_access || !current_function) - throw internal_error("invalid interface block reference"); - - r_composite_base = iface.declaration; - r_expression_result_id = 0; - r_constant_result = false; -} - void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type) { Opcode opcode; @@ -1528,10 +1518,10 @@ void SpirVGenerator::visit(StructDeclaration &strct) Id type_id = allocate_id(strct, 0); writer.write_op_name(type_id, strct.name); - if(strct.interface_block) + if(!strct.block_name.empty()) writer.write_op_decorate(type_id, DECO_BLOCK); - bool builtin = (strct.interface_block && !strct.interface_block->block_name.compare(0, 3, "gl_")); + bool builtin = !strct.block_name.compare(0, 3, "gl_"); vector member_type_ids; member_type_ids.reserve(strct.members.body.size()); for(const RefPtr &s: strct.members.body) @@ -1615,11 +1605,20 @@ void SpirVGenerator::visit(VariableDeclaration &var) } else { - StorageClass storage = (current_function ? STORAGE_FUNCTION : get_interface_storage(var.interface, false)); + bool push_const = has_layout_qualifier(var.layout.get(), "push_constant"); + + StorageClass storage; + if(current_function) + storage = STORAGE_FUNCTION; + else if(push_const) + storage = STORAGE_PUSH_CONSTANT; + else + storage = get_interface_storage(var.interface, var.block_declaration); + Id ptr_type_id = get_pointer_type_id(type_id, storage); if(var.interface=="uniform") { - Id &uni_id = declared_uniform_ids["v"+var.name]; + Id &uni_id = declared_uniform_ids[var.block_declaration ? "b"+var.block_declaration->block_name : "v"+var.name]; if(uni_id) { insert_unique(declared_ids, &var, Declaration(uni_id, ptr_type_id)); @@ -1662,7 +1661,7 @@ void SpirVGenerator::visit(VariableDeclaration &var) writer.write_op_decorate(var_id, DECO_BINDING, q.value); } } - if(!var.name.compare(0, 3, "gl_")) + if(!var.block_declaration && !var.name.compare(0, 3, "gl_")) { BuiltinSemantic semantic = get_builtin_semantic(var.name); writer.write_op_decorate(var_id, DECO_BUILTIN, semantic); @@ -1678,48 +1677,6 @@ void SpirVGenerator::visit(VariableDeclaration &var) writer.write_op_name(var_id, var.name); } -void SpirVGenerator::visit(InterfaceBlock &iface) -{ - bool push_const = has_layout_qualifier(iface.layout.get(), "push_constant"); - - StorageClass storage = (push_const ? STORAGE_PUSH_CONSTANT : get_interface_storage(iface.interface, true)); - Id type_id; - if(iface.array) - type_id = get_array_type_id(*iface.struct_declaration, 0, true); - else - type_id = get_id(*iface.struct_declaration); - Id ptr_type_id = get_pointer_type_id(type_id, storage); - - Id block_id; - if(iface.interface=="uniform") - { - Id &uni_id = declared_uniform_ids["b"+iface.block_name]; - if(uni_id) - { - insert_unique(declared_ids, &iface, Declaration(uni_id, ptr_type_id)); - return; - } - - uni_id = block_id = allocate_id(iface, ptr_type_id); - } - else - block_id = allocate_id(iface, ptr_type_id); - writer.write_op_name(block_id, iface.instance_name); - - writer.write_op(content.globals, OP_VARIABLE, ptr_type_id, block_id, storage); - - if(iface.layout) - { - for(const Layout::Qualifier &q: iface.layout->qualifiers) - { - if(q.name=="set") - writer.write_op_decorate(block_id, DECO_DESCRIPTOR_SET, q.value); - else if(q.name=="binding") - writer.write_op_decorate(block_id, DECO_BINDING, q.value); - } - } -} - void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) { writer.begin_op(content.entry_points, OP_ENTRY_POINT); @@ -1735,15 +1692,9 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) set dependencies = DependencyCollector().apply(func); for(Node *n: dependencies) - { if(const VariableDeclaration *var = dynamic_cast(n)) - { if(!var->interface.empty()) writer.write(get_id(*n)); - } - else if(dynamic_cast(n)) - writer.write(get_id(*n)); - } writer.end_op(OP_ENTRY_POINT); diff --git a/source/glsl/spirv.h b/source/glsl/spirv.h index a83478b0..23def508 100644 --- a/source/glsl/spirv.h +++ b/source/glsl/spirv.h @@ -139,7 +139,6 @@ private: virtual void visit(Block &); virtual void visit(Literal &); virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); void generate_composite_access(TypeDeclaration &); void visit_composite(Expression &, unsigned, TypeDeclaration &); void visit_isolated(Expression &); @@ -164,7 +163,6 @@ private: virtual void visit(ImageTypeDeclaration &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); void visit_entry_point(FunctionDeclaration &, Id); virtual void visit(FunctionDeclaration &); virtual void visit(Conditional &); diff --git a/source/glsl/syntax.cpp b/source/glsl/syntax.cpp index d74291bc..38a7f003 100644 --- a/source/glsl/syntax.cpp +++ b/source/glsl/syntax.cpp @@ -104,17 +104,6 @@ void VariableReference::visit(NodeVisitor &visitor) } -InterfaceBlockReference::InterfaceBlockReference(const InterfaceBlockReference &other): - Expression(other), - name(other.name) -{ } - -void InterfaceBlockReference::visit(NodeVisitor &visitor) -{ - visitor.visit(*this); -} - - MemberAccess::MemberAccess(const MemberAccess &other): Expression(other), left(other.left), @@ -249,16 +238,11 @@ StructDeclaration::StructDeclaration() StructDeclaration::StructDeclaration(const StructDeclaration &other): TypeDeclaration(other), members(other.members), + block_name(other.block_name), extended_alignment(other.extended_alignment) - // Do not copy interface block + // Do not copy block declaration { } -StructDeclaration::~StructDeclaration() -{ - if(interface_block && interface_block->struct_declaration==this) - interface_block->struct_declaration = 0; -} - void StructDeclaration::visit(NodeVisitor &visitor) { visitor.visit(*this); @@ -278,7 +262,7 @@ VariableDeclaration::VariableDeclaration(const VariableDeclaration &other): array(other.array), array_size(other.array_size), init_expression(other.init_expression) - // Do not copy type and linked declarations + // Do not copy pointers to other nodes { } VariableDeclaration::~VariableDeclaration() @@ -293,31 +277,6 @@ void VariableDeclaration::visit(NodeVisitor &visitor) } -InterfaceBlock::InterfaceBlock(const InterfaceBlock &other): - Statement(other), - layout(other.layout), - interface(other.interface), - block_name(other.block_name), - members(other.members), - instance_name(other.instance_name), - array(other.array) - // Do not copy pointers to other nodes -{ } - -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) -{ - visitor.visit(*this); -} - - FunctionDeclaration::FunctionDeclaration(const FunctionDeclaration &other): Statement(other), return_type(other.return_type), @@ -403,7 +362,7 @@ string get_unused_variable_name(const Block &block, const string &base) } } -const TypeDeclaration *get_ultimate_base_type(const TypeDeclaration *type) +TypeDeclaration *get_ultimate_base_type(TypeDeclaration *type) { if(!type) return 0; diff --git a/source/glsl/syntax.h b/source/glsl/syntax.h index 7a372dc5..95347e1b 100644 --- a/source/glsl/syntax.h +++ b/source/glsl/syntax.h @@ -111,7 +111,6 @@ class NodeArray: public NodeContainer > > struct TypeDeclaration; struct VariableDeclaration; -struct InterfaceBlock; struct FunctionDeclaration; struct Statement: Node @@ -166,19 +165,6 @@ struct VariableReference: Expression virtual void visit(NodeVisitor &); }; -struct InterfaceBlockReference: Expression -{ - std::string name; - - InterfaceBlock *declaration = 0; - - InterfaceBlockReference() = default; - InterfaceBlockReference(const InterfaceBlockReference &); - - virtual InterfaceBlockReference *clone() const { return new InterfaceBlockReference(*this); } - virtual void visit(NodeVisitor &); -}; - struct MemberAccess: Expression { NodePtr left; @@ -391,13 +377,13 @@ struct ImageTypeDeclaration: TypeDeclaration struct StructDeclaration: TypeDeclaration { Block members; + std::string block_name; bool extended_alignment = false; - InterfaceBlock *interface_block = 0; + VariableDeclaration *block_declaration = 0; StructDeclaration(); StructDeclaration(const StructDeclaration &); - ~StructDeclaration(); virtual StructDeclaration *clone() const { return new StructDeclaration(*this); } virtual void visit(NodeVisitor &); @@ -418,6 +404,7 @@ struct VariableDeclaration: Statement NodePtr init_expression; TypeDeclaration *type_declaration = 0; + StructDeclaration *block_declaration = 0; VariableDeclaration *linked_declaration = 0; VariableDeclaration() = default; @@ -428,29 +415,6 @@ struct VariableDeclaration: Statement virtual void visit(NodeVisitor &); }; -struct InterfaceBlock: Statement -{ - NodePtr layout; - std::string interface; - std::string block_name; - NodePtr members; - std::string instance_name; - bool array = false; - - /* 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 = 0; - StructDeclaration *struct_declaration = 0; - InterfaceBlock *linked_block = 0; - - InterfaceBlock() = default; - InterfaceBlock(const InterfaceBlock &); - ~InterfaceBlock(); - - virtual InterfaceBlock *clone() const { return new InterfaceBlock(*this); } - virtual void visit(NodeVisitor &); -}; - struct FunctionDeclaration: Statement { std::string return_type; @@ -530,7 +494,7 @@ struct Stage Stage *previous = 0; Block content; std::map types; - std::map interface_blocks; + std::map interface_blocks; std::map functions; std::map locations; std::map texture_bindings; @@ -554,7 +518,7 @@ struct Module }; std::string get_unused_variable_name(const Block &, const std::string &); -const TypeDeclaration *get_ultimate_base_type(const TypeDeclaration *); +TypeDeclaration *get_ultimate_base_type(TypeDeclaration *); bool has_layout_qualifier(const Layout *, const std::string &); int get_layout_value(const Layout *, const std::string &, int = -1); void add_layout_qualifier(RefPtr &, const Layout::Qualifier &); diff --git a/source/glsl/validate.cpp b/source/glsl/validate.cpp index 1d0192fe..f43217ce 100644 --- a/source/glsl/validate.cpp +++ b/source/glsl/validate.cpp @@ -212,13 +212,14 @@ void DeclarationValidator::visit(ImageTypeDeclaration &type) void DeclarationValidator::visit(StructDeclaration &strct) { - SetForScope set_scope(scope, (scope!=INTERFACE_BLOCK ? STRUCT : scope)); + SetForScope set_scope(scope, (strct.block_name.empty() ? STRUCT : INTERFACE_BLOCK)); + SetForScope set_iface(iface_block, strct.block_declaration); TraversingVisitor::visit(strct); } void DeclarationValidator::visit(VariableDeclaration &var) { - SetForScope set_var(variable, &var); + SetForScope set_var((var.block_declaration ? iface_block : variable), &var); const char *descr = describe_variable(scope); @@ -275,6 +276,13 @@ void DeclarationValidator::visit(VariableDeclaration &var) else if(scope==GLOBAL && var.interface!="uniform") error(var, format("Type '%s' only allowed with uniform interface", type->name)); } + else if(var.block_declaration) + { + if(stage->type==Stage::VERTEX && var.interface=="in") + error(var, "Interface block not allowed on vertex shader input"); + else if(stage->type==Stage::FRAGMENT && var.interface=="out") + error(var, "Interface block not allowed on fragment shader output"); + } else if(kind==BasicTypeDeclaration::VOID) error(var, "Type 'void' not allowed on variable"); else if(kind==BasicTypeDeclaration::BOOL && var.source!=BUILTIN_SOURCE) @@ -296,21 +304,6 @@ void DeclarationValidator::visit(VariableDeclaration &var) } } -void DeclarationValidator::visit(InterfaceBlock &iface) -{ - SetForScope set_scope(scope, INTERFACE_BLOCK); - SetForScope set_iface(iface_block, &iface); - - if(stage->type==Stage::VERTEX && iface.interface=="in") - error(iface, "Interface block not allowed on vertex shader input"); - else if(stage->type==Stage::FRAGMENT && iface.interface=="out") - error(iface, "Interface block not allowed on fragment shader output"); - - TraversingVisitor::visit(iface); - if(iface.struct_declaration) - iface.struct_declaration->visit(*this); -} - void DeclarationValidator::visit(FunctionDeclaration &func) { SetForScope set_scope(scope, FUNCTION_PARAM); @@ -362,42 +355,43 @@ void IdentifierValidator::visit(TypeDeclaration &type) void IdentifierValidator::visit(StructDeclaration &strct) { - check_definition(strct.name, strct); + if(strct.block_name.empty()) + check_definition(strct.name, strct); TraversingVisitor::visit(strct); } void IdentifierValidator::visit(VariableDeclaration &var) { - check_definition(var.name, var); - TraversingVisitor::visit(var); -} + if(var.block_declaration) + { + string key = format("%s %s", var.interface, var.block_declaration->block_name); + auto i = interface_blocks.find(key); + if(i!=interface_blocks.end()) + multiple_definition(format("interface block '%s %s'", var.interface, var.block_declaration->block_name), var, *i->second); + else + interface_blocks.insert(make_pair(key, &var)); -void IdentifierValidator::visit(InterfaceBlock &iface) -{ - string key = format("%s %s", iface.interface, iface.block_name); - auto i = interface_blocks.find(key); - if(i!=interface_blocks.end()) - multiple_definition(format("interface block '%s %s'", iface.interface, iface.block_name), iface, *i->second); - else - interface_blocks.insert(make_pair(key, &iface)); + if(Statement *previous = find_definition(var.block_declaration->block_name)) + { + const VariableDeclaration *prev_var = dynamic_cast(previous); + if(!prev_var || !prev_var->block_declaration) + multiple_definition(format("'%s'", var.block_declaration->block_name), var, *previous); + } + else + record_definition(var.block_declaration->block_name, var); - if(Statement *previous = find_definition(iface.block_name)) - { - if(!dynamic_cast(previous)) - multiple_definition(format("'%s'", iface.block_name), iface, *previous); + if(var.name.find(' ')!=string::npos) + { + // Inject anonymous interface block members into the global scope + for(const auto &kvp: var.block_declaration->members.variables) + check_definition(kvp.first, *kvp.second); + } } - else - record_definition(iface.block_name, iface); - if(!iface.instance_name.empty()) - check_definition(iface.instance_name, iface); + if(var.name.find(' ')==string::npos) + check_definition(var.name, var); - if(iface.instance_name.empty() && iface.struct_declaration) - { - // Inject anonymous interface block members into the global scope - for(const auto &kvp: iface.struct_declaration->members.variables) - check_definition(kvp.first, *kvp.second); - } + TraversingVisitor::visit(var); } void IdentifierValidator::visit(FunctionDeclaration &func) @@ -445,7 +439,7 @@ void ReferenceValidator::visit(VariableReference &var) if(!var.declaration) error(var, format("Use of undeclared variable '%s'", var.name)); else if(stage->type!=Stage::VERTEX && var.declaration->interface=="in" && var.name.compare(0, 3, "gl_") && !var.declaration->linked_declaration) - error(var, format("Use of unlinked input variable '%s'", var.name)); + error(var, format("Use of unlinked input %s '%s'", (var.declaration->block_declaration ? "block" : "variable"), var.name)); } void ReferenceValidator::visit(MemberAccess &memacc) @@ -455,16 +449,6 @@ void ReferenceValidator::visit(MemberAccess &memacc) TraversingVisitor::visit(memacc); } -void ReferenceValidator::visit(InterfaceBlockReference &iface) -{ - /* An interface block reference without a declaration should be impossible - since references are generated based on existing declarations. */ - if(!iface.declaration) - error(iface, format("Use of undeclared interface block '%s'", iface.name)); - else if(stage->type!=Stage::VERTEX && iface.declaration->interface=="in" && !iface.declaration->linked_block) - error(iface, format("Use of unlinked input block '%s'", iface.name)); -} - void ReferenceValidator::visit(FunctionCall &call) { if((!call.constructor && !call.declaration) || (call.constructor && !call.type)) @@ -504,13 +488,6 @@ 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.block_name)); - TraversingVisitor::visit(iface); -} - void ReferenceValidator::visit(FunctionDeclaration &func) { if(!func.return_type_declaration) @@ -524,7 +501,10 @@ void ExpressionValidator::visit(VariableReference &var) if(var.declaration && constant_expression) { if(!var.declaration->constant) - error(var, format("Reference to non-constant variable '%s' in a constant expression", var.name)); + { + const char *kind = (var.declaration->block_declaration ? "interface block" : "non-constant variable"); + error(var, format("Reference to %s '%s' in a constant expression", kind, var.name)); + } else if(var.declaration->layout && constant_expression==FIXED_CONSTANT) { if(has_layout_qualifier(var.declaration->layout.get(), "constant_id")) @@ -533,12 +513,6 @@ void ExpressionValidator::visit(VariableReference &var) } } -void ExpressionValidator::visit(InterfaceBlockReference &iface) -{ - if(constant_expression) - error(iface, format("Reference to interface block '%s' in a constant expression", iface.name)); -} - void ExpressionValidator::visit(Swizzle &swizzle) { unsigned size = 0; @@ -902,11 +876,14 @@ void GlobalInterfaceValidator::visit(VariableDeclaration &var) Uniform uni; uni.node = &var; uni.type = var.type_declaration; - uni.name = var.name; + uni.name = (var.block_declaration ? var.block_declaration->block_name : var.name); if(var.layout) { - uni.location = get_layout_value(var.layout.get(), "location"); - uni.loc_count = LocationCounter().apply(var); + if(!var.block_declaration) + { + uni.location = get_layout_value(var.layout.get(), "location"); + uni.loc_count = LocationCounter().apply(var); + } uni.desc_set = get_layout_value(var.layout.get(), "set", 0); uni.bind_point = get_layout_value(var.layout.get(), "binding"); } @@ -916,25 +893,6 @@ void GlobalInterfaceValidator::visit(VariableDeclaration &var) } } -void GlobalInterfaceValidator::visit(InterfaceBlock &iface) -{ - if(iface.interface=="uniform") - { - Uniform uni; - uni.node = &iface; - uni.type = iface.struct_declaration; - uni.name = iface.block_name; - if(iface.layout) - { - uni.desc_set = get_layout_value(iface.layout.get(), "set", 0); - uni.bind_point = get_layout_value(iface.layout.get(), "binding"); - } - - uniforms.push_back(uni); - check_uniform(uniforms.back()); - } -} - } // namespace SL } // namespace GL } // namespace Msp diff --git a/source/glsl/validate.h b/source/glsl/validate.h index a09f9f64..c9a7b736 100644 --- a/source/glsl/validate.h +++ b/source/glsl/validate.h @@ -42,7 +42,7 @@ private: Features features; ScopeType scope = GLOBAL; InterfaceLayout *iface_layout = 0; - InterfaceBlock *iface_block = 0; + VariableDeclaration *iface_block = 0; VariableDeclaration *variable = 0; public: @@ -57,7 +57,6 @@ private: virtual void visit(ImageTypeDeclaration &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); }; @@ -69,7 +68,7 @@ private: typedef std::map BlockDeclarationMap; std::map declarations; - std::map interface_blocks; + std::map interface_blocks; std::map overloaded_functions; bool anonymous_block = false; @@ -87,7 +86,6 @@ private: virtual void visit(ImageTypeDeclaration &t) { visit(static_cast(t)); } virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); }; @@ -102,10 +100,8 @@ private: virtual void visit(ImageTypeDeclaration &); virtual void visit(VariableReference &); virtual void visit(MemberAccess &); - virtual void visit(InterfaceBlockReference &); virtual void visit(FunctionCall &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); }; @@ -130,7 +126,6 @@ public: private: virtual void visit(VariableReference &); - virtual void visit(InterfaceBlockReference &); virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); @@ -207,7 +202,6 @@ private: void check_uniform(const Uniform &); 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 b0025982..bcd6051a 100644 --- a/source/glsl/visitor.cpp +++ b/source/glsl/visitor.cpp @@ -86,14 +86,6 @@ void TraversingVisitor::visit(VariableDeclaration &var) visit(var.array_size); } -void TraversingVisitor::visit(InterfaceBlock &iface) -{ - if(iface.layout) - iface.layout->visit(*this); - if(iface.members) - iface.members->visit(*this); -} - void TraversingVisitor::visit(FunctionDeclaration &func) { enter(func.body); @@ -170,11 +162,32 @@ void NodeRemover::visit(TypeDeclaration &type) remove_from_map(stage->types, type.name, type); } +void NodeRemover::visit(StructDeclaration &strct) +{ + if(to_remove->count(&strct)) + { + remove_from_map(stage->types, strct.name, strct); + if(strct.block_declaration) + { + string key = format("%s %s", strct.block_declaration->interface, strct.block_name); + remove_from_map(stage->interface_blocks, key, *strct.block_declaration); + remove_from_map(stage->interface_blocks, strct.block_declaration->name, *strct.block_declaration); + strct.block_declaration->block_declaration = 0; + } + } +} + void NodeRemover::visit(VariableDeclaration &var) { - if(recursive_remove || to_remove->count(&var)) + if(to_remove->count(&var)) { remove_from_map(current_block->variables, var.name, var); + if(var.block_declaration) + { + remove_from_map(stage->interface_blocks, format("%s %s", var.interface, var.block_declaration->block_name), var); + remove_from_map(stage->interface_blocks, var.name, var); + var.block_declaration->block_declaration = 0; + } stage->locations.erase(var.name); if(var.linked_declaration) var.linked_declaration->linked_declaration = 0; @@ -183,18 +196,6 @@ void NodeRemover::visit(VariableDeclaration &var) var.init_expression = 0; } -void NodeRemover::visit(InterfaceBlock &iface) -{ - if(to_remove->count(&iface)) - { - remove_from_map(stage->interface_blocks, format("%s %s", iface.interface, iface.block_name), iface); - if(!iface.instance_name.empty()) - remove_from_map(stage->interface_blocks, iface.instance_name, iface); - } - SetFlag set_recursive(recursive_remove, recursive_remove || to_remove->count(&iface)); - TraversingVisitor::visit(iface); -} - void NodeRemover::visit(FunctionDeclaration &func) { if(to_remove->count(&func)) diff --git a/source/glsl/visitor.h b/source/glsl/visitor.h index 622a4834..2503a15e 100644 --- a/source/glsl/visitor.h +++ b/source/glsl/visitor.h @@ -20,7 +20,6 @@ public: virtual void visit(Block &) { } virtual void visit(Literal &) { } virtual void visit(VariableReference &) { } - virtual void visit(InterfaceBlockReference &) { } virtual void visit(MemberAccess &) { } virtual void visit(Swizzle &) { } virtual void visit(UnaryExpression &) { } @@ -37,7 +36,6 @@ public: virtual void visit(ImageTypeDeclaration &) { } virtual void visit(StructDeclaration &) { } virtual void visit(VariableDeclaration &) { } - virtual void visit(InterfaceBlock &) { } virtual void visit(FunctionDeclaration &) { } virtual void visit(Conditional &) { } virtual void visit(Iteration &) { } @@ -69,7 +67,6 @@ public: virtual void visit(InterfaceLayout &); virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); virtual void visit(Conditional &); virtual void visit(Iteration &); @@ -83,7 +80,6 @@ class NodeRemover: private TraversingVisitor private: Stage *stage = 0; const std::set *to_remove = 0; - bool recursive_remove = false; public: void apply(Stage &, const std::set &); @@ -96,9 +92,8 @@ private: void visit(TypeDeclaration &); virtual void visit(BasicTypeDeclaration &t) { visit(static_cast(t)); } virtual void visit(ImageTypeDeclaration &t) { visit(static_cast(t)); } - virtual void visit(StructDeclaration &t) { visit(static_cast(t)); } + virtual void visit(StructDeclaration &); virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); virtual void visit(Iteration &); }; -- 2.43.0