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