]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/generate.cpp
Fix scoping of GLSL loop variables and function parameters
[libs/gl.git] / source / glsl / generate.cpp
1 #include <msp/core/raii.h>
2 #include "builtin.h"
3 #include "generate.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9 namespace SL {
10
11 DeclarationCombiner::DeclarationCombiner():
12         toplevel(true)
13 { }
14
15 void DeclarationCombiner::apply(Stage &stage)
16 {
17         visit(stage.content);
18         NodeRemover().apply(stage, nodes_to_remove);
19 }
20
21 void DeclarationCombiner::visit(Block &block)
22 {
23         if(!toplevel)
24                 return;
25
26         SetForScope<bool> set(toplevel, false);
27         TraversingVisitor::visit(block);
28 }
29
30 void DeclarationCombiner::visit(FunctionDeclaration &func)
31 {
32         vector<FunctionDeclaration *> &decls = functions[func.name];
33         if(func.definition)
34         {
35                 for(vector<FunctionDeclaration *>::iterator i=decls.begin(); i!=decls.end(); ++i)
36                 {
37                         (*i)->definition = func.definition;
38                         (*i)->body.body.clear();
39                 }
40         }
41         decls.push_back(&func);
42 }
43
44 void DeclarationCombiner::visit(VariableDeclaration &var)
45 {
46         VariableDeclaration *&ptr = variables[var.name];
47         if(ptr)
48         {
49                 ptr->type = var.type;
50                 if(var.init_expression)
51                         ptr->init_expression = var.init_expression;
52                 if(var.layout)
53                 {
54                         if(ptr->layout)
55                         {
56                                 for(vector<Layout::Qualifier>::iterator i=var.layout->qualifiers.begin(); i!=var.layout->qualifiers.end(); ++i)
57                                 {
58                                         bool found = false;
59                                         for(vector<Layout::Qualifier>::iterator j=ptr->layout->qualifiers.begin(); (!found && j!=ptr->layout->qualifiers.end()); ++j)
60                                                 if(j->identifier==i->identifier)
61                                                 {
62                                                         j->value = i->value;
63                                                         found = true;
64                                                 }
65
66                                         if(!found)
67                                                 ptr->layout->qualifiers.push_back(*i);
68                                 }
69                         }
70                         else
71                                 ptr->layout = var.layout;
72                 }
73                 nodes_to_remove.insert(&var);
74         }
75         else
76                 ptr = &var;
77 }
78
79
80 VariableResolver::VariableResolver():
81         anonymous(false),
82         record_target(false),
83         assignment_target(0),
84         self_referencing(false)
85 { }
86
87 void VariableResolver::apply(Stage &stage)
88 {
89         Stage *builtins = get_builtins(stage.type);
90         if(builtins)
91                 blocks.push_back(&builtins->content);
92         visit(stage.content);
93         if(builtins)
94                 blocks.pop_back();
95 }
96
97 void VariableResolver::visit(Block &block)
98 {
99         if(!blocks.empty() && blocks.back()==&block)
100                 return TraversingVisitor::visit(block);
101
102         blocks.push_back(&block);
103         block.variables.clear();
104         TraversingVisitor::visit(block);
105         blocks.pop_back();
106 }
107
108 void VariableResolver::visit(VariableReference &var)
109 {
110         var.declaration = 0;
111         type = 0;
112         for(vector<Block *>::iterator i=blocks.end(); i!=blocks.begin(); )
113         {
114                 --i;
115                 map<string, VariableDeclaration *>::iterator j = (*i)->variables.find(var.name);
116                 if(j!=(*i)->variables.end())
117                 {
118                         var.declaration = j->second;
119                         type = j->second->type_declaration;
120                         break;
121                 }
122         }
123
124         if(record_target)
125         {
126                 if(assignment_target)
127                 {
128                         record_target = false;
129                         assignment_target = 0;
130                 }
131                 else
132                         assignment_target = var.declaration;
133         }
134         else if(var.declaration && var.declaration==assignment_target)
135                 self_referencing = true;
136 }
137
138 void VariableResolver::visit(MemberAccess &memacc)
139 {
140         type = 0;
141         TraversingVisitor::visit(memacc);
142         memacc.declaration = 0;
143         if(type)
144         {
145                 map<string, VariableDeclaration *>::iterator i = type->members.variables.find(memacc.member);
146                 if(i!=type->members.variables.end())
147                 {
148                         memacc.declaration = i->second;
149                         type = i->second->type_declaration;
150                 }
151                 else
152                         type = 0;
153         }
154 }
155
156 void VariableResolver::visit(BinaryExpression &binary)
157 {
158         if(binary.oper=="[")
159         {
160                 {
161                         SetForScope<bool> set(record_target, false);
162                         binary.right->visit(*this);
163                 }
164                 type = 0;
165                 binary.left->visit(*this);
166         }
167         else
168         {
169                 TraversingVisitor::visit(binary);
170                 type = 0;
171         }
172 }
173
174 void VariableResolver::visit(Assignment &assign)
175 {
176         {
177                 SetFlag set(record_target);
178                 assignment_target = 0;
179                 assign.left->visit(*this);
180         }
181
182         self_referencing = false;
183         assign.right->visit(*this);
184
185         assign.self_referencing = (self_referencing || assign.oper!="=");
186         assign.target_declaration = assignment_target;
187 }
188
189 void VariableResolver::visit(StructDeclaration &strct)
190 {
191         TraversingVisitor::visit(strct);
192         blocks.back()->types[strct.name] = &strct;
193 }
194
195 void VariableResolver::visit(VariableDeclaration &var)
196 {
197         for(vector<Block *>::iterator i=blocks.end(); i!=blocks.begin(); )
198         {
199                 --i;
200                 map<string, StructDeclaration *>::iterator j = (*i)->types.find(var.type);
201                 if(j!=(*i)->types.end())
202                         var.type_declaration = j->second;
203         }
204
205         if(!block_interface.empty() && var.interface.empty())
206                 var.interface = block_interface;
207
208         TraversingVisitor::visit(var);
209         blocks.back()->variables[var.name] = &var;
210         if(anonymous && blocks.size()>1)
211                 blocks[blocks.size()-2]->variables[var.name] = &var;
212 }
213
214 void VariableResolver::visit(InterfaceBlock &iface)
215 {
216         SetFlag set(anonymous);
217         SetForScope<string> set2(block_interface, iface.interface);
218         TraversingVisitor::visit(iface);
219 }
220
221 void VariableResolver::visit(FunctionDeclaration &func)
222 {
223         blocks.push_back(&func.body);
224         func.body.variables.clear();
225         TraversingVisitor::visit(func);
226         blocks.pop_back();
227 }
228
229 void VariableResolver::visit(Iteration &iter)
230 {
231         blocks.push_back(&iter.body);
232         iter.body.variables.clear();
233         TraversingVisitor::visit(iter);
234         blocks.pop_back();
235 }
236
237
238 void FunctionResolver::visit(FunctionCall &call)
239 {
240         map<string, vector<FunctionDeclaration *> >::iterator i = functions.find(call.name);
241         if(i!=functions.end())
242                 call.declaration = i->second.back();
243
244         TraversingVisitor::visit(call);
245 }
246
247 void FunctionResolver::visit(FunctionDeclaration &func)
248 {
249         vector<FunctionDeclaration *> &decls = functions[func.name];
250         if(func.definition)
251         {
252                 for(vector<FunctionDeclaration *>::iterator i=decls.begin(); i!=decls.end(); ++i)
253                         (*i)->definition = func.definition;
254                 decls.clear();
255                 decls.push_back(&func);
256         }
257         else if(!decls.empty() && decls.back()->definition)
258                 func.definition = decls.back()->definition;
259         else
260                 decls.push_back(&func);
261
262         TraversingVisitor::visit(func);
263 }
264
265
266 InterfaceGenerator::InterfaceGenerator():
267         stage(0),
268         scope_level(0),
269         current_block(0)
270 { }
271
272 string InterfaceGenerator::get_out_prefix(Stage::Type type)
273 {
274         if(type==Stage::VERTEX)
275                 return "_vs_out_";
276         else if(type==Stage::GEOMETRY)
277                 return "_gs_out_";
278         else
279                 return string();
280 }
281
282 void InterfaceGenerator::apply(Stage &s)
283 {
284         stage = &s;
285         if(stage->previous)
286                 in_prefix = get_out_prefix(stage->previous->type);
287         out_prefix = get_out_prefix(stage->type);
288         visit(s.content);
289         NodeRemover().apply(s, nodes_to_remove);
290 }
291
292 void InterfaceGenerator::visit(Block &block)
293 {
294         SetForScope<unsigned> set(scope_level, scope_level+1);
295         SetForScope<Block *> set_block(current_block, &block);
296         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
297         {
298                 assignment_insert_point = i;
299                 if(scope_level==1)
300                         iface_insert_point = i;
301
302                 (*i)->visit(*this);
303         }
304 }
305
306 string InterfaceGenerator::change_prefix(const string &name, const string &prefix) const
307 {
308         unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size());
309         return prefix+name.substr(offset);
310 }
311
312 bool InterfaceGenerator::generate_interface(VariableDeclaration &var, const string &iface, const string &name)
313 {
314         const map<string, VariableDeclaration *> &stage_vars = (iface=="in" ? stage->in_variables : stage->out_variables);
315         if(stage_vars.count(name))
316                 return false;
317
318         VariableDeclaration* iface_var = new VariableDeclaration;
319         iface_var->sampling = var.sampling;
320         iface_var->interface = iface;
321         iface_var->type = var.type;
322         iface_var->type_declaration = var.type_declaration;
323         iface_var->name = name;
324         if(stage->type==Stage::GEOMETRY)
325                 iface_var->array = ((var.array && var.interface!="in") || iface=="in");
326         else
327                 iface_var->array = var.array;
328         if(iface_var->array)
329                 iface_var->array_size = var.array_size;
330         if(iface=="in")
331                 iface_var->linked_declaration = &var;
332         stage->content.body.insert(iface_insert_point, iface_var);
333         {
334                 SetForScope<unsigned> set_level(scope_level, 1);
335                 SetForScope<Block *> set_block(current_block, &stage->content);
336                 iface_var->visit(*this);
337         }
338
339         return true;
340 }
341
342 ExpressionStatement &InterfaceGenerator::insert_assignment(const string &left, Expression *right)
343 {
344         Assignment *assign = new Assignment;
345         VariableReference *ref = new VariableReference;
346         ref->name = left;
347         assign->left = ref;
348         assign->oper = "=";
349         assign->right = right;
350
351         ExpressionStatement *stmt = new ExpressionStatement;
352         stmt->expression = assign;
353         current_block->body.insert(assignment_insert_point, stmt);
354         stmt->visit(*this);
355
356         return *stmt;
357 }
358
359 void InterfaceGenerator::visit(VariableReference &var)
360 {
361         if(var.declaration || !stage->previous)
362                 return;
363
364         const map<string, VariableDeclaration *> &prev_out = stage->previous->out_variables;
365         map<string, VariableDeclaration *>::const_iterator i = prev_out.find(var.name);
366         if(i==prev_out.end())
367                 i = prev_out.find(in_prefix+var.name);
368         if(i!=prev_out.end())
369         {
370                 generate_interface(*i->second, "in", i->second->name);
371                 var.name = i->second->name;
372         }
373 }
374
375 void InterfaceGenerator::visit(VariableDeclaration &var)
376 {
377         if(var.interface=="out")
378         {
379                 if(scope_level==1)
380                         stage->out_variables[var.name] = &var;
381                 else if(generate_interface(var, "out", change_prefix(var.name, string())))
382                 {
383                         nodes_to_remove.insert(&var);
384                         if(var.init_expression)
385                         {
386                                 ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone());
387                                 stmt.source = var.source;
388                                 stmt.line = var.line;
389                                 return;
390                         }
391                 }
392         }
393         else if(var.interface=="in")
394         {
395                 stage->in_variables[var.name] = &var;
396                 if(var.linked_declaration)
397                         var.linked_declaration->linked_declaration = &var;
398                 else if(stage->previous)
399                 {
400                         const map<string, VariableDeclaration *> &prev_out = stage->previous->out_variables;
401                         map<string, VariableDeclaration *>::const_iterator i = prev_out.find(var.name);
402                         if(i!=prev_out.end())
403                         {
404                                 var.linked_declaration = i->second;
405                                 i->second->linked_declaration = &var;
406                         }
407                 }
408         }
409
410         TraversingVisitor::visit(var);
411 }
412
413 void InterfaceGenerator::visit(Passthrough &pass)
414 {
415         vector<VariableDeclaration *> pass_vars;
416
417         for(map<string, VariableDeclaration *>::const_iterator i=stage->in_variables.begin(); i!=stage->in_variables.end(); ++i)
418                 pass_vars.push_back(i->second);
419
420         if(stage->previous)
421         {
422                 const map<string, VariableDeclaration *> &prev_out = stage->previous->out_variables;
423                 for(map<string, VariableDeclaration *>::const_iterator i=prev_out.begin(); i!=prev_out.end(); ++i)
424                 {
425                         bool linked = false;
426                         for(vector<VariableDeclaration *>::const_iterator j=pass_vars.begin(); (!linked && j!=pass_vars.end()); ++j)
427                                 linked = ((*j)->linked_declaration==i->second);
428
429                         if(!linked && generate_interface(*i->second, "in", i->second->name))
430                                 pass_vars.push_back(i->second);
431                 }
432         }
433
434         if(stage->type==Stage::GEOMETRY)
435         {
436                 VariableReference *ref = new VariableReference;
437                 ref->name = "gl_in";
438
439                 BinaryExpression *subscript = new BinaryExpression;
440                 subscript->left = ref;
441                 subscript->oper = "[";
442                 subscript->right = pass.subscript;
443                 subscript->after = "]";
444
445                 MemberAccess *memacc = new MemberAccess;
446                 memacc->left = subscript;
447                 memacc->member = "gl_Position";
448
449                 insert_assignment("gl_Position", memacc);
450         }
451
452         for(vector<VariableDeclaration *>::const_iterator i=pass_vars.begin(); i!=pass_vars.end(); ++i)
453         {
454                 string out_name = change_prefix((*i)->name, out_prefix);
455                 generate_interface(**i, "out", out_name);
456
457                 VariableReference *ref = new VariableReference;
458                 ref->name = (*i)->name;
459                 if(pass.subscript)
460                 {
461                         BinaryExpression *subscript = new BinaryExpression;
462                         subscript->left = ref;
463                         subscript->oper = "[";
464                         subscript->right = pass.subscript;
465                         subscript->after = "]";
466                         insert_assignment(out_name, subscript);
467                 }
468                 else
469                         insert_assignment(out_name, ref);
470         }
471
472         nodes_to_remove.insert(&pass);
473 }
474
475
476 DeclarationReorderer::DeclarationReorderer():
477         scope_level(0),
478         kind(NO_DECLARATION)
479 { }
480
481 void DeclarationReorderer::visit(FunctionCall &call)
482 {
483         FunctionDeclaration *def = call.declaration;
484         if(def)
485                 def = def->definition;
486         if(def && !ordered_funcs.count(def))
487                 needed_funcs.insert(def);
488 }
489
490 void DeclarationReorderer::visit(Block &block)
491 {
492         SetForScope<unsigned> set(scope_level, scope_level+1);
493         if(scope_level>1)
494                 return TraversingVisitor::visit(block);
495
496         NodeList<Statement>::iterator struct_insert_point = block.body.end();
497         NodeList<Statement>::iterator variable_insert_point = block.body.end();
498         NodeList<Statement>::iterator function_insert_point = block.body.end();
499         unsigned unordered_func_count = 0;
500         bool ordered_any_funcs = false;
501
502         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); )
503         {
504                 kind = NO_DECLARATION;
505                 (*i)->visit(*this);
506
507                 bool moved = false;
508                 if(kind==STRUCT && struct_insert_point!=block.body.end())
509                 {
510                         block.body.insert(struct_insert_point, *i);
511                         moved = true;
512                 }
513                 else if(kind>STRUCT && struct_insert_point==block.body.end())
514                         struct_insert_point = i;
515
516                 if(kind==VARIABLE && variable_insert_point!=block.body.end())
517                 {
518                         block.body.insert(variable_insert_point, *i);
519                         moved = true;
520                 }
521                 else if(kind>VARIABLE && variable_insert_point==block.body.end())
522                         variable_insert_point = i;
523
524                 if(kind==FUNCTION)
525                 {
526                         if(function_insert_point==block.body.end())
527                                 function_insert_point = i;
528
529                         if(needed_funcs.empty())
530                         {
531                                 ordered_funcs.insert(i->get());
532                                 if(i!=function_insert_point)
533                                 {
534                                         block.body.insert(function_insert_point, *i);
535                                         moved = true;
536                                 }
537                                 else
538                                         ++function_insert_point;
539                                 ordered_any_funcs = true;
540                         }
541                         else
542                                 ++unordered_func_count;
543                 }
544
545                 if(moved)
546                 {
547                         if(function_insert_point==i)
548                                 ++function_insert_point;
549                         block.body.erase(i++);
550                 }
551                 else
552                         ++i;
553
554                 if(i==block.body.end() && unordered_func_count)
555                 {
556                         if(!ordered_any_funcs)
557                                 // A subset of the remaining functions forms a recursive loop
558                                 /* TODO pick a function and move it up, adding any necessary
559                                 declarations */
560                                 break;
561
562                         i = function_insert_point;
563                         unordered_func_count = 0;
564                 }
565         }
566 }
567
568 void DeclarationReorderer::visit(VariableDeclaration &var)
569 {
570         TraversingVisitor::visit(var);
571         kind = VARIABLE;
572 }
573
574 void DeclarationReorderer::visit(FunctionDeclaration &func)
575 {
576         needed_funcs.clear();
577         func.body.visit(*this);
578         needed_funcs.erase(&func);
579         kind = FUNCTION;
580 }
581
582 } // namespace SL
583 } // namespace GL
584 } // namespace Msp