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:";
{
append(strct, format("%s struct %s", get_label(strct), strct.name));
vector<Branch> 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);
vector<Branch> 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)
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<Branch> 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));
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 &);
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 &);
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);
}
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");
if(var.interface=="uniform")
{
- const TypeDeclaration *base_type = get_ultimate_base_type(var.type_declaration);
- if(dynamic_cast<const ImageTypeDeclaration *>(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<const ImageTypeDeclaration *>(base_type) && !visit_uniform(var.name, var.layout))
+ unbound_textures.push_back(&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)
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)
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<Statement> &s: iface.struct_declaration->members.body)
- if(VariableDeclaration *var = dynamic_cast<VariableDeclaration *>(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<Statement> &s: var.block_declaration->members.body)
+ if(VariableDeclaration *mem = dynamic_cast<VariableDeclaration *>(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);
}
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)
{
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());
}
else if(i->name=="binding" && !supports_binding())
{
- if(dynamic_cast<const ImageTypeDeclaration *>(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<const ImageTypeDeclaration *>(get_ultimate_base_type(var.type_declaration)))
stage->texture_bindings[var.name] = i->value;
i = var.layout->qualifiers.erase(i);
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
std::map<unsigned, std::set<unsigned> > used_bindings;
std::vector<VariableDeclaration *> unplaced_variables;
std::vector<VariableDeclaration *> unbound_textures;
- std::vector<InterfaceBlock *> unbound_blocks;
+ std::vector<VariableDeclaration *> unbound_blocks;
public:
void apply(Module &, const Features &, bool = true);
bool visit_uniform(const std::string &, RefPtr<Layout> &);
virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
virtual void visit(FunctionDeclaration &) { }
};
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
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
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;
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;
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")
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<Block *> set_target(iface_target_block, in_block->members.get());
- SetForScope<NodeList<Statement>::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<Block *> 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;
return;
}
- const map<string, InterfaceBlock *> &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<string, VariableDeclaration *> &iface_vars = kvp.second->struct_declaration->members.variables;
+ const map<string, VariableDeclaration *> &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;
}
}
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. */
previous stage. */
if(!var.linked_declaration && stage->previous)
{
- const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
- auto i = prev_vars.find(var.name);
- if(i!=prev_vars.end() && i->second->interface=="out")
+ const map<string, VariableDeclaration *> *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<string, InterfaceBlock *> &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)
{
/* 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;
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)
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 &);
};
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)
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);
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)
/* 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)
}
}
-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)
private:
virtual void visit(VariableReference &);
- virtual void visit(InterfaceBlockReference &);
virtual void visit(FunctionCall &);
virtual void visit(VariableDeclaration &);
virtual void visit(Return &);
virtual void visit(BinaryExpression &);
virtual void visit(StructDeclaration &) { }
virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &) { }
virtual void visit(FunctionDeclaration &);
};
virtual void visit(ImageTypeDeclaration &);
virtual void visit(StructDeclaration &);
virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
virtual void visit(FunctionDeclaration &);
};
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 &);
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 &);
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)
void Formatter::visit(StructDeclaration &strct)
{
+ if(!strct.block_name.empty())
+ return;
+
append(format("struct %s\n", strct.name));
strct.members.visit(*this);
append(';');
}
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('[');
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));
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 &);
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 &);
allow_stage_change = true;
while(!tokenizer.peek_token().empty())
if(RefPtr<Statement> 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"));
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);
}
else if(is_interface_qualifier(token) && tokenizer.peek_token(2)=="{")
{
- RefPtr<InterfaceBlock> iface = parse_interface_block();
- iface->layout = layout;
- return iface;
+ RefPtr<StructDeclaration> 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
{
if(is_type(next) || is_qualifier(next))
return parse_variable_declaration();
else
- return parse_interface_block();
+ {
+ RefPtr<StructDeclaration> iface_strct = parse_interface_block();
+ next_global_declaration = iface_strct->block_declaration;
+ return iface_strct;
+ }
}
else if(is_qualifier(token))
return parse_variable_declaration();
return func;
}
-RefPtr<InterfaceBlock> Parser::parse_interface_block()
+RefPtr<StructDeclaration> Parser::parse_interface_block()
{
- RefPtr<InterfaceBlock> iface = create_node<InterfaceBlock>();
-
- iface->interface = tokenizer.parse_token();
- if(!is_interface_qualifier(iface->interface))
- throw parse_error(tokenizer.get_location(), iface->interface, "an interface qualifier");
+ RefPtr<StructDeclaration> strct = create_node<StructDeclaration>();
+ RefPtr<VariableDeclaration> var = create_node<VariableDeclaration>();
- 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<Conditional> Parser::parse_conditional()
std::set<std::string> global_types;
std::set<std::string> stage_types;
std::vector<std::string> errors;
+ RefPtr<Statement> next_global_declaration;
public:
Parser(ModuleCache *);
RefPtr<VariableDeclaration> parse_variable_declaration();
RefPtr<VariableDeclaration> parse_variable_declaration_with_layout();
RefPtr<FunctionDeclaration> parse_function_declaration();
- RefPtr<InterfaceBlock> parse_interface_block();
+ RefPtr<StructDeclaration> parse_interface_block();
RefPtr<Conditional> parse_conditional();
RefPtr<Iteration> parse_for();
RefPtr<Iteration> parse_while();
}
}
-void DependencyCollector::visit(InterfaceBlockReference &iface)
-{
- if(iface.declaration)
- {
- dependencies.insert(iface.declaration);
- iface.declaration->visit(*this);
- }
-}
-
void DependencyCollector::visit(FunctionCall &call)
{
if(call.declaration)
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]=='-'));
private:
virtual void visit(VariableReference &);
- virtual void visit(InterfaceBlockReference &);
virtual void visit(FunctionCall &);
virtual void visit(VariableDeclaration &);
virtual void visit(FunctionDeclaration &);
private:
virtual void visit(VariableReference &);
- virtual void visit(InterfaceBlockReference &);
virtual void visit(UnaryExpression &);
virtual void visit(BinaryExpression &);
virtual void visit(Assignment &);
void TypeResolver::visit(StructDeclaration &strct)
{
stage->types.insert(make_pair(strct.name, &strct));
- SetForScope<InterfaceBlock *> set_iface(iface_block, strct.interface_block);
- TraversingVisitor::visit(strct);
+ if(strct.block_name.empty())
+ {
+ SetForScope<VariableDeclaration *> 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<StructDeclaration *>(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<NodeList<Statement>::iterator> set_ins_pt(type_insert_point, block_member_type_ins_pt);
+ SetForScope<VariableDeclaration *> set_iface(iface_block, &var);
+ TraversingVisitor::visit(*strct);
+ }
+
if(iface_block)
{
if(var.interface==iface_block->interface)
}
}
-void TypeResolver::visit(InterfaceBlock &iface)
-{
- if(iface.members)
- {
- SetForScope<InterfaceBlock *> 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);
if(!declaration)
{
- const map<string, InterfaceBlock *> &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;
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);
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);
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<string, InterfaceBlock *> &blocks = stage->interface_blocks;
+ const map<string, VariableDeclaration *> &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<string, VariableDeclaration *> &block_vars = j->second->struct_declaration->members.variables;
- i = block_vars.find(var.name);
- if(i!=block_vars.end())
+ const map<string, VariableDeclaration *> &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;
}
}
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<string, VariableDeclaration *> &vars = var.block_declaration->members.variables;
+ const map<string, VariableDeclaration *> &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);
}
}
-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<string, VariableDeclaration *> &vars = iface.struct_declaration->members.variables;
- const map<string, VariableDeclaration *> &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)
{
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);
std::map<TypeDeclaration *, TypeDeclaration *> alias_map;
std::map<std::pair<TypeDeclaration *, bool>, TypeDeclaration *> array_types;
NodeList<Statement>::iterator type_insert_point;
- InterfaceBlock *iface_block = 0;
+ NodeList<Statement>::iterator block_member_type_ins_pt;
+ VariableDeclaration *iface_block = 0;
bool r_any_resolved = false;
public:
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:
virtual void visit(RefPtr<Expression> &);
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 &);
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. */
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 &);
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;
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<Id> member_type_ids;
member_type_ids.reserve(strct.members.body.size());
for(const RefPtr<Statement> &s: strct.members.body)
}
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));
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);
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);
set<Node *> dependencies = DependencyCollector().apply(func);
for(Node *n: dependencies)
- {
if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(n))
- {
if(!var->interface.empty())
writer.write(get_id(*n));
- }
- else if(dynamic_cast<InterfaceBlock *>(n))
- writer.write(get_id(*n));
- }
writer.end_op(OP_ENTRY_POINT);
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 &);
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 &);
}
-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),
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);
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()
}
-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),
}
}
-const TypeDeclaration *get_ultimate_base_type(const TypeDeclaration *type)
+TypeDeclaration *get_ultimate_base_type(TypeDeclaration *type)
{
if(!type)
return 0;
struct TypeDeclaration;
struct VariableDeclaration;
-struct InterfaceBlock;
struct FunctionDeclaration;
struct Statement: Node
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<Expression> left;
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 &);
NodePtr<Expression> init_expression;
TypeDeclaration *type_declaration = 0;
+ StructDeclaration *block_declaration = 0;
VariableDeclaration *linked_declaration = 0;
VariableDeclaration() = default;
virtual void visit(NodeVisitor &);
};
-struct InterfaceBlock: Statement
-{
- NodePtr<Layout> layout;
- std::string interface;
- std::string block_name;
- NodePtr<Block> 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;
Stage *previous = 0;
Block content;
std::map<std::string, TypeDeclaration *> types;
- std::map<std::string, InterfaceBlock *> interface_blocks;
+ std::map<std::string, VariableDeclaration *> interface_blocks;
std::map<std::string, FunctionDeclaration *> functions;
std::map<std::string, unsigned> locations;
std::map<std::string, unsigned> texture_bindings;
};
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<Layout> &, const Layout::Qualifier &);
void DeclarationValidator::visit(StructDeclaration &strct)
{
- SetForScope<ScopeType> set_scope(scope, (scope!=INTERFACE_BLOCK ? STRUCT : scope));
+ SetForScope<ScopeType> set_scope(scope, (strct.block_name.empty() ? STRUCT : INTERFACE_BLOCK));
+ SetForScope<VariableDeclaration *> set_iface(iface_block, strct.block_declaration);
TraversingVisitor::visit(strct);
}
void DeclarationValidator::visit(VariableDeclaration &var)
{
- SetForScope<VariableDeclaration *> set_var(variable, &var);
+ SetForScope<VariableDeclaration *> set_var((var.block_declaration ? iface_block : variable), &var);
const char *descr = describe_variable(scope);
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)
}
}
-void DeclarationValidator::visit(InterfaceBlock &iface)
-{
- SetForScope<ScopeType> set_scope(scope, INTERFACE_BLOCK);
- SetForScope<InterfaceBlock *> 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<ScopeType> set_scope(scope, FUNCTION_PARAM);
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<const VariableDeclaration *>(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<InterfaceBlock *>(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)
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)
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))
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)
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"))
}
}
-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;
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");
}
}
}
-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
Features features;
ScopeType scope = GLOBAL;
InterfaceLayout *iface_layout = 0;
- InterfaceBlock *iface_block = 0;
+ VariableDeclaration *iface_block = 0;
VariableDeclaration *variable = 0;
public:
virtual void visit(ImageTypeDeclaration &);
virtual void visit(StructDeclaration &);
virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
virtual void visit(FunctionDeclaration &);
};
typedef std::map<std::string, Statement *> BlockDeclarationMap;
std::map<Block *, BlockDeclarationMap> declarations;
- std::map<std::string, InterfaceBlock *> interface_blocks;
+ std::map<std::string, VariableDeclaration *> interface_blocks;
std::map<std::string, FunctionDeclaration *> overloaded_functions;
bool anonymous_block = false;
virtual void visit(ImageTypeDeclaration &t) { visit(static_cast<TypeDeclaration &>(t)); }
virtual void visit(StructDeclaration &);
virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
virtual void visit(FunctionDeclaration &);
};
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 &);
};
private:
virtual void visit(VariableReference &);
- virtual void visit(InterfaceBlockReference &);
virtual void visit(Swizzle &);
virtual void visit(UnaryExpression &);
virtual void visit(BinaryExpression &);
void check_uniform(const Uniform &);
virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
virtual void visit(FunctionDeclaration &) { }
};
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);
remove_from_map(stage->types, type.name, type);
}
+void NodeRemover::visit(StructDeclaration &strct)
+{
+ if(to_remove->count(&strct))
+ {
+ remove_from_map<TypeDeclaration>(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;
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))
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 &) { }
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 &) { }
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 &);
private:
Stage *stage = 0;
const std::set<Node *> *to_remove = 0;
- bool recursive_remove = false;
public:
void apply(Stage &, const std::set<Node *> &);
void visit(TypeDeclaration &);
virtual void visit(BasicTypeDeclaration &t) { visit(static_cast<TypeDeclaration &>(t)); }
virtual void visit(ImageTypeDeclaration &t) { visit(static_cast<TypeDeclaration &>(t)); }
- virtual void visit(StructDeclaration &t) { visit(static_cast<TypeDeclaration &>(t)); }
+ virtual void visit(StructDeclaration &);
virtual void visit(VariableDeclaration &);
- virtual void visit(InterfaceBlock &);
virtual void visit(FunctionDeclaration &);
virtual void visit(Iteration &);
};