+#include <msp/core/algorithm.h>
#include <msp/core/hash.h>
#include <msp/core/raii.h>
#include "generate.h"
void ConstantIdAssigner::apply(Module &module, const Features &features)
{
- for(list<Stage>::iterator i=module.stages.begin(); i!=module.stages.end(); ++i)
- i->content.visit(*this);
+ for(Stage &s: module.stages)
+ s.content.visit(*this);
- unsigned max_id = features.max_constant_id;
- for(vector<VariableDeclaration *>::iterator i=auto_constants.begin(); i!=auto_constants.end(); ++i)
+ for(VariableDeclaration *v: auto_constants)
{
- unsigned id = hash32((*i)->name)%(max_id+1);
- while(used_ids.count(id))
- ++id;
+ unsigned id;
+ auto j = existing_constants.find(v->name);
+ if(j!=existing_constants.end())
+ id = j->second;
+ else
+ {
+ id = hash<32>(v->name)%features.constant_id_range;
+ while(used_ids.count(id))
+ id = (id+1)%features.constant_id_range;
+ }
- vector<Layout::Qualifier> &qualifiers = (*i)->layout->qualifiers;
- for(vector<Layout::Qualifier>::iterator j=qualifiers.begin(); j!=qualifiers.end(); ++j)
- if(j->name=="constant_id")
- {
- j->value = id;
- break;
- }
+ auto i = find_member(v->layout->qualifiers, string("constant_id"), &Layout::Qualifier::name);
+ if(i!=v->layout->qualifiers.end())
+ i->value = id;
used_ids.insert(id);
+ existing_constants[v->name] = id;
}
}
{
if(var.layout)
{
- vector<Layout::Qualifier> &qualifiers = var.layout->qualifiers;
- for(vector<Layout::Qualifier>::iterator i=qualifiers.begin(); i!=qualifiers.end(); ++i)
- if(i->name=="constant_id" && i->has_value)
+ auto i = find_member(var.layout->qualifiers, string("constant_id"), &Layout::Qualifier::name);
+ if(i!=var.layout->qualifiers.end() && i->has_value)
+ {
+ if(i->value==-1)
+ auto_constants.push_back(&var);
+ else
{
- if(i->value==-1)
- auto_constants.push_back(&var);
- else
- used_ids.insert(i->value);
- break;
+ existing_constants[var.name] = i->value;
+ used_ids.insert(i->value);
}
+ }
}
}
-InterfaceGenerator::InterfaceGenerator():
- stage(0),
- function_scope(false),
- copy_block(false),
- iface_target_block(0)
-{ }
-
string InterfaceGenerator::get_out_prefix(Stage::Type type)
{
if(type==Stage::VERTEX)
void InterfaceGenerator::visit(Block &block)
{
SetForScope<Block *> set_block(current_block, &block);
- for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
+ for(auto i=block.body.begin(); i!=block.body.end(); ++i)
{
assignment_insert_point = i;
if(&block==&stage->content)
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));
-
- SetFlag set_scope(function_scope, false);
- SetForScope<Block *> set_block(current_block, &stage->content);
- in_block->visit(*this);
+ string::size_type start = dot+1;
+ dot = left.find('.', start);
- 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, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
- map<string, VariableDeclaration *>::const_iterator i = prev_vars.find(var.name);
+ auto i = prev_vars.find(var.name);
if(i==prev_vars.end() || i->second->interface!="out")
i = prev_vars.find(in_prefix+var.name);
if(i!=prev_vars.end() && i->second->interface=="out")
return;
}
- const map<string, InterfaceBlock *> &prev_blocks = stage->previous->interface_blocks;
- map<string, InterfaceBlock *>::const_iterator j = prev_blocks.find("_"+var.name);
- if(j!=prev_blocks.end() && j->second->interface=="out")
- {
- generate_interface(*j->second);
- /* Let VariableResolver convert the variable reference into an interface
- block reference. */
- return;
- }
-
- for(j=prev_blocks.begin(); j!=prev_blocks.end(); ++j)
- if(j->second->instance_name.empty() && j->second->struct_declaration)
+ for(const auto &kvp: stage->previous->interface_blocks)
+ if(kvp.first.find(' ')!=string::npos)
{
- const map<string, VariableDeclaration *> &iface_vars = j->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(*j->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;
- map<string, VariableDeclaration *>::const_iterator 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;
- map<string, InterfaceBlock *>::const_iterator 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)
if(stage->previous)
{
- const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
- for(map<string, VariableDeclaration *>::const_iterator i=prev_vars.begin(); i!=prev_vars.end(); ++i)
+ for(const auto &kvp: stage->previous->content.variables)
{
- if(i->second->interface!="out")
+ if(kvp.second->interface!="out")
continue;
/* Pass through output variables from the previous stage, but only
those which are not already linked to an input here. */
- if(!i->second->linked_declaration && generate_interface(*i->second, "in", i->second->name))
- pass_vars.push_back(i->second);
+ if(!kvp.second->linked_declaration && generate_interface(*kvp.second, "in", kvp.second->name))
+ pass_vars.push_back(kvp.second);
}
}
{
/* 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(vector<VariableDeclaration *>::const_iterator i=pass_vars.begin(); i!=pass_vars.end(); ++i)
+ for(VariableDeclaration *v: pass_vars)
{
- string out_name = change_prefix((*i)->name, out_prefix);
- generate_interface(**i, "out", out_name);
+ string out_name = change_prefix(v->name, out_prefix);
+ generate_interface(*v, "out", out_name);
VariableReference *ref = new VariableReference;
- ref->name = (*i)->name;
+ ref->name = v->name;
if(pass.subscript)
{
BinaryExpression *subscript = new BinaryExpression;
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