1 #include <msp/core/algorithm.h>
2 #include <msp/core/hash.h>
3 #include <msp/core/raii.h>
12 void ConstantIdAssigner::apply(Module &module, const Features &features)
14 for(Stage &s: module.stages)
15 s.content.visit(*this);
17 for(VariableDeclaration *v: auto_constants)
20 auto j = existing_constants.find(v->name);
21 if(j!=existing_constants.end())
25 id = hash<32>(v->name)%features.constant_id_range;
26 while(used_ids.count(id))
27 id = (id+1)%features.constant_id_range;
30 auto i = find_member(v->layout->qualifiers, string("constant_id"), &Layout::Qualifier::name);
31 if(i!=v->layout->qualifiers.end())
35 existing_constants[v->name] = id;
39 void ConstantIdAssigner::visit(VariableDeclaration &var)
43 auto i = find_member(var.layout->qualifiers, string("constant_id"), &Layout::Qualifier::name);
44 if(i!=var.layout->qualifiers.end() && i->has_value)
47 auto_constants.push_back(&var);
50 existing_constants[var.name] = i->value;
51 used_ids.insert(i->value);
58 string InterfaceGenerator::get_out_prefix(Stage::Type type)
60 if(type==Stage::VERTEX)
62 else if(type==Stage::GEOMETRY)
68 void InterfaceGenerator::apply(Stage &s)
71 iface_target_block = &stage->content;
73 in_prefix = get_out_prefix(stage->previous->type);
74 out_prefix = get_out_prefix(stage->type);
75 s.content.visit(*this);
76 NodeRemover().apply(s, nodes_to_remove);
79 void InterfaceGenerator::visit(Block &block)
81 SetForScope<Block *> set_block(current_block, &block);
82 for(auto i=block.body.begin(); i!=block.body.end(); ++i)
84 assignment_insert_point = i;
85 if(&block==&stage->content)
86 iface_insert_point = i;
92 string InterfaceGenerator::change_prefix(const string &name, const string &prefix) const
94 unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size());
95 return prefix+name.substr(offset);
98 VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration &var, const string &iface, const string &name)
100 if(stage->content.variables.count(name))
103 if(stage->type==Stage::GEOMETRY && var.interface=="out" && var.array)
106 VariableDeclaration* iface_var = new VariableDeclaration;
107 iface_var->sampling = var.sampling;
108 iface_var->interface = iface;
109 iface_var->type = var.type;
110 iface_var->name = name;
111 // Tessellation and geometry inputs may be arrayed.
112 if(stage->type==Stage::TESS_CONTROL)
113 // VS out -> TCS in: add | TCS in -> TCS out: unchanged | VS out -> TCS out: add
114 iface_var->array = (var.array || var.interface!="in");
115 else if(stage->type==Stage::TESS_EVAL)
116 // TCS out -> TES in: unchanged | TES in -> TES out: remove | TCS out -> TES out: remove
117 iface_var->array = (var.array && iface=="in");
118 else if(stage->type==Stage::GEOMETRY)
119 // VS/TES out -> GS in: add | GS in -> GS out: remove | VS/TES out -> GS out: unchanged
120 iface_var->array = ((var.array && var.interface!="in") || iface=="in");
122 iface_var->array = var.array;
124 iface_var->array_size = var.array_size;
127 iface_var->layout = var.layout;
128 iface_var->linked_declaration = &var;
129 var.linked_declaration = iface_var;
132 if(var.block_declaration)
134 StructDeclaration *iface_type = var.block_declaration->clone();
135 iface_type->name = format("_%s_%s", iface, var.block_declaration->block_name);
136 iface_target_block->body.insert(iface_insert_point, iface_type);
138 iface_var->type = iface_type->name;
140 iface_var->name = format("%s %s", iface, var.block_declaration->block_name);
142 stage->interface_blocks.insert(make_pair("in "+var.block_declaration->block_name, iface_var));
144 stage->interface_blocks.insert(make_pair(name, iface_var));
147 iface_target_block->body.insert(iface_insert_point, iface_var);
148 iface_target_block->variables.insert(make_pair(name, iface_var));
149 if(iface_target_block==&stage->content && iface=="in")
150 declared_inputs.push_back(iface_var);
155 ExpressionStatement &InterfaceGenerator::insert_assignment(const string &left, Expression *right)
157 Assignment *assign = new Assignment;
159 string::size_type dot = left.find('.');
160 VariableReference *ref = new VariableReference;
161 ref->name = left.substr(0, dot);
164 while(dot!=string::npos)
166 string::size_type start = dot+1;
167 dot = left.find('.', start);
169 MemberAccess *memacc = new MemberAccess;
170 memacc->left = assign->left;
171 memacc->member = left.substr(start, dot-start);
172 assign->left = memacc;
175 assign->oper = &Operator::get_operator("=", Operator::BINARY);
176 assign->right = right;
178 ExpressionStatement *stmt = new ExpressionStatement;
179 stmt->expression = assign;
180 current_block->body.insert(assignment_insert_point, stmt);
186 void InterfaceGenerator::visit(VariableReference &var)
188 if(var.declaration || !stage->previous)
190 /* Don't pull a variable from previous stage if we just generated an output
191 interface in this stage */
192 if(stage->content.variables.count(var.name))
195 const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
196 auto i = prev_vars.find(var.name);
197 if(i==prev_vars.end() || i->second->interface!="out")
198 i = prev_vars.find(in_prefix+var.name);
199 if(i!=prev_vars.end() && i->second->interface=="out")
201 if(stage->type==Stage::GEOMETRY && i->second->array)
202 stage->diagnostics.push_back(Diagnostic(Diagnostic::WARN, var.source, var.line,
203 format("Can't access '%s' through automatic interface because it's an array", var.name)));
206 generate_interface(*i->second, "in", i->second->name);
207 var.name = i->second->name;
212 for(const auto &kvp: stage->previous->interface_blocks)
213 if(kvp.second->name.find(' ')!=string::npos)
215 const map<string, VariableDeclaration *> &iface_vars = kvp.second->block_declaration->members.variables;
216 i = iface_vars.find(var.name);
217 if(i!=iface_vars.end())
219 generate_interface(*kvp.second, "in", string());
225 void InterfaceGenerator::visit(VariableDeclaration &var)
227 if(var.interface=="out")
229 /* For output variables in function scope, generate a global interface
230 and replace the local declaration with an assignment. */
231 VariableDeclaration *out_var = 0;
232 if(function_scope && (out_var=generate_interface(var, "out", var.name)))
234 out_var->source = var.source;
235 out_var->line = var.line;
236 nodes_to_remove.insert(&var);
237 if(var.init_expression)
239 ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone());
240 stmt.source = var.source;
241 stmt.line = var.line;
246 else if(var.interface=="in" && current_block==&stage->content)
248 if(var.name.compare(0, 3, "gl_"))
249 declared_inputs.push_back(&var);
251 /* Try to link input variables in global scope with output variables from
253 if(!var.linked_declaration && stage->previous)
255 const map<string, VariableDeclaration *> *prev_vars;
257 // Blocks are linked by their block name, not instance name
258 if(var.block_declaration)
260 prev_vars = &stage->previous->interface_blocks;
261 name = "out "+var.block_declaration->block_name;
265 prev_vars = &stage->previous->content.variables;
269 auto i = prev_vars->find(name);
270 if(i!=prev_vars->end() && i->second->interface=="out")
272 var.linked_declaration = i->second;
273 i->second->linked_declaration = &var;
278 TraversingVisitor::visit(var);
281 void InterfaceGenerator::visit(FunctionDeclaration &func)
283 SetFlag set_scope(function_scope, true);
284 // Skip parameters because they're not useful here
285 func.body.visit(*this);
288 void InterfaceGenerator::visit(Passthrough &pass)
290 // Pass through all input variables declared so far.
291 vector<VariableDeclaration *> pass_vars = declared_inputs;
295 for(const auto &kvp: stage->previous->content.variables)
297 if(kvp.second->interface!="out")
300 /* Pass through output variables from the previous stage, but only
301 those which are not already linked to an input here. */
302 if(!kvp.second->linked_declaration && generate_interface(*kvp.second, "in", kvp.second->name))
303 pass_vars.push_back(kvp.second);
307 if(stage->type==Stage::GEOMETRY)
309 /* Special case for geometry shader: copy gl_Position from input to
311 VariableReference *ref = new VariableReference;
314 BinaryExpression *subscript = new BinaryExpression;
315 subscript->left = ref;
316 subscript->oper = &Operator::get_operator("[", Operator::BINARY);
317 subscript->right = pass.subscript;
319 MemberAccess *memacc = new MemberAccess;
320 memacc->left = subscript;
321 memacc->member = "gl_Position";
323 insert_assignment("out gl_PerVertex.gl_Position", memacc);
326 for(VariableDeclaration *v: pass_vars)
328 string out_name = change_prefix(v->name, out_prefix);
329 generate_interface(*v, "out", out_name);
331 VariableReference *ref = new VariableReference;
335 BinaryExpression *subscript = new BinaryExpression;
336 subscript->left = ref;
337 subscript->oper = &Operator::get_operator("[", Operator::BINARY);
338 subscript->right = pass.subscript;
339 insert_assignment(out_name, subscript);
342 insert_assignment(out_name, ref);
345 nodes_to_remove.insert(&pass);
349 void LayoutDefaulter::apply(Stage &stage)
351 if(stage.type==Stage::TESS_EVAL)
353 stage.content.visit(*this);
354 if((need_winding || need_spacing) && in_iface)
357 in_iface->layout.qualifiers.emplace_back("ccw");
359 in_iface->layout.qualifiers.emplace_back("equal_spacing");
364 void LayoutDefaulter::visit(InterfaceLayout &iface)
366 if(iface.interface=="in")
370 for(const Layout::Qualifier &q: iface.layout.qualifiers)
372 if(q.name=="cw" || q.name=="ccw")
373 need_winding = false;
374 else if(q.name=="equal_spacing" || q.name=="fractional_even_spacing" || q.name=="fractional_odd_spacing")
375 need_spacing = false;
381 void ArraySizer::apply(Stage &stage)
383 stage.content.visit(*this);
384 for(const auto &kvp: max_indices)
385 if(kvp.first->array && !kvp.first->array_size)
388 if(stage.type==Stage::GEOMETRY && kvp.first->interface=="in")
390 else if(kvp.second>=0)
392 if(!size && !kvp.first->name.compare(0, 3, "gl_"))
397 Literal *literal_size = new Literal;
398 literal_size->token = lexical_cast<string>(size);
399 literal_size->value = size;
400 kvp.first->array_size = literal_size;
405 void ArraySizer::visit(VariableReference &var)
407 r_declaration = var.declaration;
410 void ArraySizer::visit(MemberAccess &memacc)
413 TraversingVisitor::visit(memacc);
414 VariableDeclaration *member_declaration = 0;
416 if(StructDeclaration *strct = dynamic_cast<StructDeclaration *>(r_declaration->type_declaration))
418 auto i = strct->members.variables.find(memacc.member);
419 if(i!=strct->members.variables.end())
420 member_declaration = i->second;
422 r_declaration = member_declaration;
425 void ArraySizer::visit(Swizzle &swizzle)
427 TraversingVisitor::visit(swizzle);
431 void ArraySizer::visit(UnaryExpression &unary)
433 TraversingVisitor::visit(unary);
437 void ArraySizer::visit(BinaryExpression &binary)
439 if(binary.oper->token[0]=='[')
440 if(const Literal *literal_index = dynamic_cast<const Literal *>(binary.right.get()))
441 if(literal_index->value.check_type<int>())
444 binary.left->visit(*this);
447 max_indices[r_declaration] = literal_index->value.value<int>();
452 TraversingVisitor::visit(binary);
455 void ArraySizer::visit(TernaryExpression &ternary)
457 TraversingVisitor::visit(ternary);
461 void ArraySizer::visit(FunctionCall &call)
463 TraversingVisitor::visit(call);
467 void ArraySizer::visit(InterfaceLayout &layout)
469 if(layout.interface=="in")
471 for(const Layout::Qualifier &q: layout.layout.qualifiers)
475 else if(q.name=="lines")
477 else if(q.name=="triangles")
479 else if(q.name=="lines_adjacency")
481 else if(q.name=="triangles_adjacency")
487 void ArraySizer::visit(VariableDeclaration &var)
489 if(var.array && !var.array_size)
490 max_indices[&var] = 0;