id = j->second;
else
{
- id = hash32(v->name)%features.constant_id_range;
+ id = hash<32>(v->name)%features.constant_id_range;
while(used_ids.count(id))
id = (id+1)%features.constant_id_range;
}
i->value = id;
used_ids.insert(id);
+ existing_constants[v->name] = id;
}
}
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.second->name.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)
nodes_to_remove.insert(&pass);
}
+
+void ArraySizer::apply(Stage &stage)
+{
+ stage.content.visit(*this);
+ for(const auto &kvp: max_indices)
+ if(kvp.first->array && !kvp.first->array_size)
+ {
+ int size = 0;
+ if(stage.type==Stage::GEOMETRY && kvp.first->interface=="in")
+ size = input_size;
+ else if(kvp.second>=0)
+ size = kvp.second+1;
+ else if(!kvp.first->name.compare(0, 3, "gl_"))
+ size = 1;
+
+ if(size>0)
+ {
+ Literal *literal_size = new Literal;
+ literal_size->token = lexical_cast<string>(size);
+ literal_size->value = size;
+ kvp.first->array_size = literal_size;
+ }
+ }
+}
+
+void ArraySizer::visit(VariableReference &var)
+{
+ r_declaration = var.declaration;
+}
+
+void ArraySizer::visit(MemberAccess &memacc)
+{
+ r_declaration = 0;
+ TraversingVisitor::visit(memacc);
+ VariableDeclaration *member_declaration = 0;
+ if(r_declaration)
+ if(StructDeclaration *strct = dynamic_cast<StructDeclaration *>(r_declaration->type_declaration))
+ {
+ auto i = strct->members.variables.find(memacc.member);
+ if(i!=strct->members.variables.end())
+ member_declaration = i->second;
+ }
+ r_declaration = member_declaration;
+}
+
+void ArraySizer::visit(Swizzle &swizzle)
+{
+ TraversingVisitor::visit(swizzle);
+ r_declaration = 0;
+}
+
+void ArraySizer::visit(UnaryExpression &unary)
+{
+ TraversingVisitor::visit(unary);
+ r_declaration = 0;
+}
+
+void ArraySizer::visit(BinaryExpression &binary)
+{
+ if(binary.oper->token[0]=='[')
+ if(const Literal *literal_index = dynamic_cast<const Literal *>(binary.right.get()))
+ if(literal_index->value.check_type<int>())
+ {
+ r_declaration = 0;
+ binary.left->visit(*this);
+ if(r_declaration)
+ {
+ max_indices[r_declaration] = literal_index->value.value<int>();
+ return;
+ }
+ }
+
+ TraversingVisitor::visit(binary);
+}
+
+void ArraySizer::visit(TernaryExpression &ternary)
+{
+ TraversingVisitor::visit(ternary);
+ r_declaration = 0;
+}
+
+void ArraySizer::visit(FunctionCall &call)
+{
+ TraversingVisitor::visit(call);
+ r_declaration = 0;
+}
+
+void ArraySizer::visit(InterfaceLayout &layout)
+{
+ if(layout.interface=="in")
+ {
+ for(const Layout::Qualifier &q: layout.layout.qualifiers)
+ {
+ if(q.name=="points")
+ input_size = 1;
+ else if(q.name=="lines")
+ input_size = 2;
+ else if(q.name=="triangles")
+ input_size = 3;
+ else if(q.name=="lines_adjacency")
+ input_size = 4;
+ else if(q.name=="triangles_adjacency")
+ input_size = 6;
+ }
+ }
+}
+
+void ArraySizer::visit(VariableDeclaration &var)
+{
+ if(var.array && !var.array_size)
+ max_indices[&var] = 0;
+}
+
} // namespace SL
} // namespace GL
} // namespace Msp