]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/generate.cpp
Only generate or link interfaces in the correct scope
[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         current_block->interfaces.insert(&iface);
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 i = block->variables.find(var.name);
118                 if(i!=block->variables.end())
119                         var.declaration = i->second;
120                 else
121                 {
122                         const set<InterfaceBlock *> &ifaces = block->interfaces;
123                         for(set<InterfaceBlock *>::const_iterator j=ifaces.begin(); (!var.declaration && j!=ifaces.end()); ++j)
124                         {
125                                 i = (*j)->members.variables.find(var.name);
126                                 if(i!=(*j)->members.variables.end())
127                                         var.declaration = i->second;
128                         }
129                 }
130
131                 if(var.declaration)
132                 {
133                         type = var.declaration->type_declaration;
134                         break;
135                 }
136         }
137
138         if(record_target)
139         {
140                 if(assignment_target)
141                 {
142                         record_target = false;
143                         assignment_target = 0;
144                 }
145                 else
146                         assignment_target = var.declaration;
147         }
148         else if(var.declaration && var.declaration==assignment_target)
149                 self_referencing = true;
150 }
151
152 void VariableResolver::visit(MemberAccess &memacc)
153 {
154         type = 0;
155         TraversingVisitor::visit(memacc);
156         memacc.declaration = 0;
157         if(type)
158         {
159                 map<string, VariableDeclaration *>::iterator i = type->members.variables.find(memacc.member);
160                 if(i!=type->members.variables.end())
161                 {
162                         memacc.declaration = i->second;
163                         type = i->second->type_declaration;
164                 }
165                 else
166                         type = 0;
167         }
168 }
169
170 void VariableResolver::visit(BinaryExpression &binary)
171 {
172         if(binary.oper=="[")
173         {
174                 {
175                         SetForScope<bool> set(record_target, false);
176                         binary.right->visit(*this);
177                 }
178                 type = 0;
179                 binary.left->visit(*this);
180         }
181         else
182         {
183                 TraversingVisitor::visit(binary);
184                 type = 0;
185         }
186 }
187
188 void VariableResolver::visit(Assignment &assign)
189 {
190         {
191                 SetFlag set(record_target);
192                 assignment_target = 0;
193                 assign.left->visit(*this);
194         }
195
196         self_referencing = false;
197         assign.right->visit(*this);
198
199         assign.self_referencing = (self_referencing || assign.oper!="=");
200         assign.target_declaration = assignment_target;
201 }
202
203 void VariableResolver::visit(StructDeclaration &strct)
204 {
205         TraversingVisitor::visit(strct);
206         current_block->types[strct.name] = &strct;
207 }
208
209 void VariableResolver::visit(VariableDeclaration &var)
210 {
211         for(Block *block=current_block; block; block=next_block(*block))
212         {
213                 map<string, StructDeclaration *>::iterator j = block->types.find(var.type);
214                 if(j!=block->types.end())
215                         var.type_declaration = j->second;
216         }
217
218         if(!block_interface.empty() && var.interface.empty())
219                 var.interface = block_interface;
220
221         TraversingVisitor::visit(var);
222         current_block->variables[var.name] = &var;
223 }
224
225 void VariableResolver::visit(InterfaceBlock &iface)
226 {
227         SetForScope<string> set_iface(block_interface, iface.interface);
228         TraversingVisitor::visit(iface);
229 }
230
231
232 void FunctionResolver::visit(FunctionCall &call)
233 {
234         map<string, vector<FunctionDeclaration *> >::iterator i = functions.find(call.name);
235         if(i!=functions.end())
236                 call.declaration = i->second.back();
237
238         TraversingVisitor::visit(call);
239 }
240
241 void FunctionResolver::visit(FunctionDeclaration &func)
242 {
243         vector<FunctionDeclaration *> &decls = functions[func.name];
244         if(func.definition)
245         {
246                 for(vector<FunctionDeclaration *>::iterator i=decls.begin(); i!=decls.end(); ++i)
247                         (*i)->definition = func.definition;
248                 decls.clear();
249                 decls.push_back(&func);
250         }
251         else if(!decls.empty() && decls.back()->definition)
252                 func.definition = decls.back()->definition;
253         else
254                 decls.push_back(&func);
255
256         TraversingVisitor::visit(func);
257 }
258
259
260 InterfaceGenerator::InterfaceGenerator():
261         stage(0),
262         function_scope(false)
263 { }
264
265 string InterfaceGenerator::get_out_prefix(Stage::Type type)
266 {
267         if(type==Stage::VERTEX)
268                 return "_vs_out_";
269         else if(type==Stage::GEOMETRY)
270                 return "_gs_out_";
271         else
272                 return string();
273 }
274
275 void InterfaceGenerator::apply(Stage &s)
276 {
277         stage = &s;
278         if(stage->previous)
279                 in_prefix = get_out_prefix(stage->previous->type);
280         out_prefix = get_out_prefix(stage->type);
281         s.content.visit(*this);
282         NodeRemover().apply(s, nodes_to_remove);
283 }
284
285 void InterfaceGenerator::visit(Block &block)
286 {
287         SetForScope<Block *> set_block(current_block, &block);
288         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
289         {
290                 assignment_insert_point = i;
291                 if(&block==&stage->content)
292                         iface_insert_point = i;
293
294                 (*i)->visit(*this);
295         }
296 }
297
298 string InterfaceGenerator::change_prefix(const string &name, const string &prefix) const
299 {
300         unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size());
301         return prefix+name.substr(offset);
302 }
303
304 bool InterfaceGenerator::generate_interface(VariableDeclaration &var, const string &iface, const string &name)
305 {
306         if(stage->content.variables.count(name))
307                 return false;
308
309         VariableDeclaration* iface_var = new VariableDeclaration;
310         iface_var->sampling = var.sampling;
311         iface_var->interface = iface;
312         iface_var->type = var.type;
313         iface_var->type_declaration = var.type_declaration;
314         iface_var->name = name;
315         if(stage->type==Stage::GEOMETRY)
316                 iface_var->array = ((var.array && var.interface!="in") || iface=="in");
317         else
318                 iface_var->array = var.array;
319         if(iface_var->array)
320                 iface_var->array_size = var.array_size;
321         if(iface=="in")
322         {
323                 iface_var->linked_declaration = &var;
324                 var.linked_declaration = iface_var;
325         }
326         stage->content.body.insert(iface_insert_point, iface_var);
327         stage->content.variables[name] = iface_var;
328
329         return true;
330 }
331
332 ExpressionStatement &InterfaceGenerator::insert_assignment(const string &left, Expression *right)
333 {
334         Assignment *assign = new Assignment;
335         VariableReference *ref = new VariableReference;
336         ref->name = left;
337         assign->left = ref;
338         assign->oper = "=";
339         assign->right = right;
340
341         ExpressionStatement *stmt = new ExpressionStatement;
342         stmt->expression = assign;
343         current_block->body.insert(assignment_insert_point, stmt);
344         stmt->visit(*this);
345
346         return *stmt;
347 }
348
349 void InterfaceGenerator::visit(VariableReference &var)
350 {
351         if(var.declaration || !stage->previous)
352                 return;
353         /* Don't pull a variable from previous stage if we just generated an out
354         interface in this stage */
355         if(stage->content.variables.count(var.name))
356                 return;
357
358         const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
359         map<string, VariableDeclaration *>::const_iterator i = prev_vars.find(var.name);
360         if(i==prev_vars.end() || i->second->interface!="out")
361                 i = prev_vars.find(in_prefix+var.name);
362         if(i!=prev_vars.end() && i->second->interface=="out")
363         {
364                 generate_interface(*i->second, "in", i->second->name);
365                 var.name = i->second->name;
366         }
367 }
368
369 void InterfaceGenerator::visit(VariableDeclaration &var)
370 {
371         if(var.interface=="out")
372         {
373                 /* For out variables in function scope, generate a global interface and
374                 replace the local declaration with an assignment. */
375                 if(function_scope && generate_interface(var, "out", var.name))
376                 {
377                         nodes_to_remove.insert(&var);
378                         if(var.init_expression)
379                         {
380                                 ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone());
381                                 stmt.source = var.source;
382                                 stmt.line = var.line;
383                                 return;
384                         }
385                 }
386         }
387         else if(var.interface=="in")
388         {
389                 /* Try to link in variables in global scope with out variables from
390                 previous stage */
391                 if(current_block==&stage->content && !var.linked_declaration && stage->previous)
392                 {
393                         const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
394                         map<string, VariableDeclaration *>::const_iterator i = prev_vars.find(var.name);
395                         if(i!=prev_vars.end() && i->second->interface=="out")
396                         {
397                                 var.linked_declaration = i->second;
398                                 i->second->linked_declaration = &var;
399                         }
400                 }
401         }
402
403         TraversingVisitor::visit(var);
404 }
405
406 void InterfaceGenerator::visit(FunctionDeclaration &func)
407 {
408         SetFlag set_scope(function_scope, true);
409         // Skip parameters because they're not useful here
410         func.body.visit(*this);
411 }
412
413 void InterfaceGenerator::visit(Passthrough &pass)
414 {
415         vector<VariableDeclaration *> pass_vars;
416
417         for(map<string, VariableDeclaration *>::const_iterator i=stage->content.variables.begin(); i!=stage->content.variables.end(); ++i)
418                 if(i->second->interface=="in")
419                         pass_vars.push_back(i->second);
420
421         if(stage->previous)
422         {
423                 const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
424                 for(map<string, VariableDeclaration *>::const_iterator i=prev_vars.begin(); i!=prev_vars.end(); ++i)
425                 {
426                         bool linked = false;
427                         for(vector<VariableDeclaration *>::const_iterator j=pass_vars.begin(); (!linked && j!=pass_vars.end()); ++j)
428                                 linked = ((*j)->linked_declaration==i->second);
429
430                         if(!linked && generate_interface(*i->second, "in", i->second->name))
431                                 pass_vars.push_back(i->second);
432                 }
433         }
434
435         if(stage->type==Stage::GEOMETRY)
436         {
437                 VariableReference *ref = new VariableReference;
438                 ref->name = "gl_in";
439
440                 BinaryExpression *subscript = new BinaryExpression;
441                 subscript->left = ref;
442                 subscript->oper = "[";
443                 subscript->right = pass.subscript;
444                 subscript->after = "]";
445
446                 MemberAccess *memacc = new MemberAccess;
447                 memacc->left = subscript;
448                 memacc->member = "gl_Position";
449
450                 insert_assignment("gl_Position", memacc);
451         }
452
453         for(vector<VariableDeclaration *>::const_iterator i=pass_vars.begin(); i!=pass_vars.end(); ++i)
454         {
455                 string out_name = change_prefix((*i)->name, out_prefix);
456                 generate_interface(**i, "out", out_name);
457
458                 VariableReference *ref = new VariableReference;
459                 ref->name = (*i)->name;
460                 if(pass.subscript)
461                 {
462                         BinaryExpression *subscript = new BinaryExpression;
463                         subscript->left = ref;
464                         subscript->oper = "[";
465                         subscript->right = pass.subscript;
466                         subscript->after = "]";
467                         insert_assignment(out_name, subscript);
468                 }
469                 else
470                         insert_assignment(out_name, ref);
471         }
472
473         nodes_to_remove.insert(&pass);
474 }
475
476
477 DeclarationReorderer::DeclarationReorderer():
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         if(block.parent)
493                 return TraversingVisitor::visit(block);
494
495         NodeList<Statement>::iterator struct_insert_point = block.body.end();
496         NodeList<Statement>::iterator variable_insert_point = block.body.end();
497         NodeList<Statement>::iterator function_insert_point = block.body.end();
498         unsigned unordered_func_count = 0;
499         bool ordered_any_funcs = false;
500
501         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); )
502         {
503                 kind = NO_DECLARATION;
504                 (*i)->visit(*this);
505
506                 bool moved = false;
507                 if(kind==STRUCT && struct_insert_point!=block.body.end())
508                 {
509                         block.body.insert(struct_insert_point, *i);
510                         moved = true;
511                 }
512                 else if(kind>STRUCT && struct_insert_point==block.body.end())
513                         struct_insert_point = i;
514
515                 if(kind==VARIABLE && variable_insert_point!=block.body.end())
516                 {
517                         block.body.insert(variable_insert_point, *i);
518                         moved = true;
519                 }
520                 else if(kind>VARIABLE && variable_insert_point==block.body.end())
521                         variable_insert_point = i;
522
523                 if(kind==FUNCTION)
524                 {
525                         if(function_insert_point==block.body.end())
526                                 function_insert_point = i;
527
528                         if(needed_funcs.empty())
529                         {
530                                 ordered_funcs.insert(i->get());
531                                 if(i!=function_insert_point)
532                                 {
533                                         block.body.insert(function_insert_point, *i);
534                                         moved = true;
535                                 }
536                                 else
537                                         ++function_insert_point;
538                                 ordered_any_funcs = true;
539                         }
540                         else
541                                 ++unordered_func_count;
542                 }
543
544                 if(moved)
545                 {
546                         if(function_insert_point==i)
547                                 ++function_insert_point;
548                         block.body.erase(i++);
549                 }
550                 else
551                         ++i;
552
553                 if(i==block.body.end() && unordered_func_count)
554                 {
555                         if(!ordered_any_funcs)
556                                 // A subset of the remaining functions forms a recursive loop
557                                 /* TODO pick a function and move it up, adding any necessary
558                                 declarations */
559                                 break;
560
561                         i = function_insert_point;
562                         unordered_func_count = 0;
563                 }
564         }
565 }
566
567 void DeclarationReorderer::visit(VariableDeclaration &var)
568 {
569         TraversingVisitor::visit(var);
570         kind = VARIABLE;
571 }
572
573 void DeclarationReorderer::visit(FunctionDeclaration &func)
574 {
575         needed_funcs.clear();
576         func.body.visit(*this);
577         needed_funcs.erase(&func);
578         kind = FUNCTION;
579 }
580
581 } // namespace SL
582 } // namespace GL
583 } // namespace Msp