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)