]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/generate.cpp
Split glsl/generate.cpp in two
[libs/gl.git] / source / glsl / generate.cpp
1 #include <msp/core/hash.h>
2 #include <msp/core/raii.h>
3 #include "generate.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9 namespace SL {
10
11 ConstantSpecializer::ConstantSpecializer():
12         values(0)
13 { }
14
15 void ConstantSpecializer::apply(Stage &stage, const map<string, int> *v)
16 {
17         values = v;
18         stage.content.visit(*this);
19 }
20
21 void ConstantSpecializer::visit(VariableDeclaration &var)
22 {
23         bool specializable = false;
24         if(var.layout)
25         {
26                 vector<Layout::Qualifier> &qualifiers = var.layout->qualifiers;
27                 for(vector<Layout::Qualifier>::iterator i=qualifiers.begin(); i!=qualifiers.end(); ++i)
28                         if(i->name=="constant_id")
29                         {
30                                 specializable = true;
31                                 if(values)
32                                         qualifiers.erase(i);
33                                 else if(i->value==-1)
34                                         i->value = hash32(var.name)&0x7FFFFFFF;
35                                 break;
36                         }
37
38                 if(qualifiers.empty())
39                         var.layout = 0;
40         }
41
42         if(specializable && values)
43         {
44                 map<string, int>::const_iterator i = values->find(var.name);
45                 if(i!=values->end())
46                 {
47                         RefPtr<Literal> literal = new Literal;
48                         if(var.type=="bool")
49                         {
50                                 literal->token = (i->second ? "true" : "false");
51                                 literal->value = static_cast<bool>(i->second);
52                         }
53                         else if(var.type=="int")
54                         {
55                                 literal->token = lexical_cast<string>(i->second);
56                                 literal->value = i->second;
57                         }
58                         var.init_expression = literal;
59                 }
60         }
61 }
62
63
64 InterfaceGenerator::InterfaceGenerator():
65         stage(0),
66         function_scope(false),
67         copy_block(false),
68         iface_target_block(0)
69 { }
70
71 string InterfaceGenerator::get_out_prefix(Stage::Type type)
72 {
73         if(type==Stage::VERTEX)
74                 return "_vs_out_";
75         else if(type==Stage::GEOMETRY)
76                 return "_gs_out_";
77         else
78                 return string();
79 }
80
81 void InterfaceGenerator::apply(Stage &s)
82 {
83         stage = &s;
84         iface_target_block = &stage->content;
85         if(stage->previous)
86                 in_prefix = get_out_prefix(stage->previous->type);
87         out_prefix = get_out_prefix(stage->type);
88         s.content.visit(*this);
89         NodeRemover().apply(s, nodes_to_remove);
90 }
91
92 void InterfaceGenerator::visit(Block &block)
93 {
94         SetForScope<Block *> set_block(current_block, &block);
95         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
96         {
97                 assignment_insert_point = i;
98                 if(&block==&stage->content)
99                         iface_insert_point = i;
100
101                 (*i)->visit(*this);
102         }
103 }
104
105 string InterfaceGenerator::change_prefix(const string &name, const string &prefix) const
106 {
107         unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size());
108         return prefix+name.substr(offset);
109 }
110
111 VariableDeclaration *InterfaceGenerator::generate_interface(VariableDeclaration &var, const string &iface, const string &name)
112 {
113         if(stage->content.variables.count(name))
114                 return 0;
115
116         if(stage->type==Stage::GEOMETRY && !copy_block && var.interface=="out" && var.array)
117                 return 0;
118
119         VariableDeclaration* iface_var = new VariableDeclaration;
120         iface_var->sampling = var.sampling;
121         iface_var->interface = iface;
122         iface_var->type = var.type;
123         iface_var->name = name;
124         /* Geometry shader inputs are always arrays.  But if we're bringing in an
125         entire block, the array is on the block and not individual variables. */
126         if(stage->type==Stage::GEOMETRY && !copy_block)
127                 iface_var->array = ((var.array && var.interface!="in") || iface=="in");
128         else
129                 iface_var->array = var.array;
130         if(iface_var->array)
131                 iface_var->array_size = var.array_size;
132         if(iface=="in")
133         {
134                 iface_var->layout = var.layout;
135                 iface_var->linked_declaration = &var;
136                 var.linked_declaration = iface_var;
137         }
138
139         iface_target_block->body.insert(iface_insert_point, iface_var);
140         iface_target_block->variables.insert(make_pair(name, iface_var));
141         if(iface_target_block==&stage->content && iface=="in")
142                 declared_inputs.push_back(iface_var);
143
144         return iface_var;
145 }
146
147 InterfaceBlock *InterfaceGenerator::generate_interface(InterfaceBlock &out_block)
148 {
149         if(stage->interface_blocks.count("in"+out_block.block_name))
150                 return 0;
151
152         InterfaceBlock *in_block = new InterfaceBlock;
153         in_block->interface = "in";
154         in_block->block_name = out_block.block_name;
155         in_block->members = new Block;
156         in_block->instance_name = out_block.instance_name;
157         if(stage->type==Stage::GEOMETRY)
158                 in_block->array = true;
159         else
160                 in_block->array = out_block.array;
161         in_block->linked_block = &out_block;
162         out_block.linked_block = in_block;
163
164         {
165                 SetFlag set_copy(copy_block, true);
166                 SetForScope<Block *> set_target(iface_target_block, in_block->members.get());
167                 SetForScope<NodeList<Statement>::iterator> set_ins_pt(iface_insert_point, in_block->members->body.end());
168                 if(out_block.struct_declaration)
169                         out_block.struct_declaration->members.visit(*this);
170                 else if(out_block.members)
171                         out_block.members->visit(*this);
172         }
173
174         iface_target_block->body.insert(iface_insert_point, in_block);
175         stage->interface_blocks.insert(make_pair("in"+in_block->block_name, in_block));
176         if(!in_block->instance_name.empty())
177                 stage->interface_blocks.insert(make_pair("_"+in_block->instance_name, in_block));
178
179         SetFlag set_scope(function_scope, false);
180         SetForScope<Block *> set_block(current_block, &stage->content);
181         in_block->visit(*this);
182
183         return in_block;
184 }
185
186 ExpressionStatement &InterfaceGenerator::insert_assignment(const string &left, Expression *right)
187 {
188         Assignment *assign = new Assignment;
189         VariableReference *ref = new VariableReference;
190         ref->name = left;
191         assign->left = ref;
192         assign->oper = &Operator::get_operator("=", Operator::BINARY);
193         assign->right = right;
194
195         ExpressionStatement *stmt = new ExpressionStatement;
196         stmt->expression = assign;
197         current_block->body.insert(assignment_insert_point, stmt);
198         stmt->visit(*this);
199
200         return *stmt;
201 }
202
203 void InterfaceGenerator::visit(VariableReference &var)
204 {
205         if(var.declaration || !stage->previous)
206                 return;
207         /* Don't pull a variable from previous stage if we just generated an output
208         interface in this stage */
209         if(stage->content.variables.count(var.name))
210                 return;
211
212         const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
213         map<string, VariableDeclaration *>::const_iterator i = prev_vars.find(var.name);
214         if(i==prev_vars.end() || i->second->interface!="out")
215                 i = prev_vars.find(in_prefix+var.name);
216         if(i!=prev_vars.end() && i->second->interface=="out")
217         {
218                 if(stage->type==Stage::GEOMETRY && i->second->array)
219                         stage->diagnostics.push_back(Diagnostic(Diagnostic::WARN, var.source, var.line,
220                                 format("Can't access '%s' through automatic interface because it's an array", var.name)));
221                 else
222                 {
223                         generate_interface(*i->second, "in", i->second->name);
224                         var.name = i->second->name;
225                 }
226                 return;
227         }
228
229         const map<string, InterfaceBlock *> &prev_blocks = stage->previous->interface_blocks;
230         map<string, InterfaceBlock *>::const_iterator j = prev_blocks.find("_"+var.name);
231         if(j!=prev_blocks.end() && j->second->interface=="out")
232         {
233                 generate_interface(*j->second);
234                 /* Let VariableResolver convert the variable reference into an interface
235                 block reference. */
236                 return;
237         }
238
239         for(j=prev_blocks.begin(); j!=prev_blocks.end(); ++j)
240                 if(j->second->instance_name.empty() && j->second->struct_declaration)
241                 {
242                         const map<string, VariableDeclaration *> &iface_vars = j->second->struct_declaration->members.variables;
243                         i = iface_vars.find(var.name);
244                         if(i!=iface_vars.end())
245                         {
246                                 generate_interface(*j->second);
247                                 return;
248                         }
249                 }
250 }
251
252 void InterfaceGenerator::visit(VariableDeclaration &var)
253 {
254         if(copy_block)
255                 generate_interface(var, "in", var.name);
256         else if(var.interface=="out")
257         {
258                 /* For output variables in function scope, generate a global interface
259                 and replace the local declaration with an assignment. */
260                 VariableDeclaration *out_var = 0;
261                 if(function_scope && (out_var=generate_interface(var, "out", var.name)))
262                 {
263                         out_var->source = var.source;
264                         out_var->line = var.line;
265                         nodes_to_remove.insert(&var);
266                         if(var.init_expression)
267                         {
268                                 ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone());
269                                 stmt.source = var.source;
270                                 stmt.line = var.line;
271                                 return;
272                         }
273                 }
274         }
275         else if(var.interface=="in" && current_block==&stage->content)
276         {
277                 if(var.name.compare(0, 3, "gl_"))
278                         declared_inputs.push_back(&var);
279
280                 /* Try to link input variables in global scope with output variables from
281                 previous stage. */
282                 if(!var.linked_declaration && stage->previous)
283                 {
284                         const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
285                         map<string, VariableDeclaration *>::const_iterator i = prev_vars.find(var.name);
286                         if(i!=prev_vars.end() && i->second->interface=="out")
287                         {
288                                 var.linked_declaration = i->second;
289                                 i->second->linked_declaration = &var;
290                         }
291                 }
292         }
293
294         TraversingVisitor::visit(var);
295 }
296
297 void InterfaceGenerator::visit(InterfaceBlock &iface)
298 {
299         if(iface.interface=="in")
300         {
301                 /* Try to link input blocks with output blocks sharing the same block
302                 name from previous stage. */
303                 if(!iface.linked_block && stage->previous)
304                 {
305                         const map<string, InterfaceBlock *> &prev_blocks = stage->previous->interface_blocks;
306                         map<string, InterfaceBlock *>::const_iterator i = prev_blocks.find("out"+iface.block_name);
307                         if(i!=prev_blocks.end())
308                         {
309                                 iface.linked_block = i->second;
310                                 i->second->linked_block = &iface;
311                         }
312                 }
313         }
314
315         TraversingVisitor::visit(iface);
316 }
317
318 void InterfaceGenerator::visit(FunctionDeclaration &func)
319 {
320         SetFlag set_scope(function_scope, true);
321         // Skip parameters because they're not useful here
322         func.body.visit(*this);
323 }
324
325 void InterfaceGenerator::visit(Passthrough &pass)
326 {
327         // Pass through all input variables declared so far.
328         vector<VariableDeclaration *> pass_vars = declared_inputs;
329
330         if(stage->previous)
331         {
332                 const map<string, VariableDeclaration *> &prev_vars = stage->previous->content.variables;
333                 for(map<string, VariableDeclaration *>::const_iterator i=prev_vars.begin(); i!=prev_vars.end(); ++i)
334                 {
335                         if(i->second->interface!="out")
336                                 continue;
337
338                         /* Pass through output variables from the previous stage, but only
339                         those which are not already linked to an input here. */
340                         if(!i->second->linked_declaration && generate_interface(*i->second, "in", i->second->name))
341                                 pass_vars.push_back(i->second);
342                 }
343         }
344
345         if(stage->type==Stage::GEOMETRY)
346         {
347                 /* Special case for geometry shader: copy gl_Position from input to
348                 output. */
349                 InterfaceBlockReference *ref = new InterfaceBlockReference;
350                 ref->name = "gl_in";
351
352                 BinaryExpression *subscript = new BinaryExpression;
353                 subscript->left = ref;
354                 subscript->oper = &Operator::get_operator("[", Operator::BINARY);
355                 subscript->right = pass.subscript;
356
357                 MemberAccess *memacc = new MemberAccess;
358                 memacc->left = subscript;
359                 memacc->member = "gl_Position";
360
361                 insert_assignment("gl_Position", memacc);
362         }
363
364         for(vector<VariableDeclaration *>::const_iterator i=pass_vars.begin(); i!=pass_vars.end(); ++i)
365         {
366                 string out_name = change_prefix((*i)->name, out_prefix);
367                 generate_interface(**i, "out", out_name);
368
369                 VariableReference *ref = new VariableReference;
370                 ref->name = (*i)->name;
371                 if(pass.subscript)
372                 {
373                         BinaryExpression *subscript = new BinaryExpression;
374                         subscript->left = ref;
375                         subscript->oper = &Operator::get_operator("[", Operator::BINARY);
376                         subscript->right = pass.subscript;
377                         insert_assignment(out_name, subscript);
378                 }
379                 else
380                         insert_assignment(out_name, ref);
381         }
382
383         nodes_to_remove.insert(&pass);
384 }
385
386 } // namespace SL
387 } // namespace GL
388 } // namespace Msp