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