]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/reflect.cpp
Clear load ID when assigning to a component
[libs/gl.git] / source / glsl / reflect.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/core/raii.h>
3 #include "reflect.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace GL {
9 namespace SL {
10
11 bool is_scalar(const BasicTypeDeclaration &type)
12 {
13         return (type.kind==BasicTypeDeclaration::INT || type.kind==BasicTypeDeclaration::FLOAT);
14 }
15
16 bool is_vector_or_matrix(const BasicTypeDeclaration &type)
17 {
18         return (type.kind==BasicTypeDeclaration::VECTOR || type.kind==BasicTypeDeclaration::MATRIX);
19 }
20
21 BasicTypeDeclaration *get_element_type(BasicTypeDeclaration &type)
22 {
23         if(is_vector_or_matrix(type) || type.kind==BasicTypeDeclaration::ARRAY)
24         {
25                 BasicTypeDeclaration *basic_base = dynamic_cast<BasicTypeDeclaration *>(type.base_type);
26                 return (basic_base ? get_element_type(*basic_base) : 0);
27         }
28         else
29                 return &type;
30 }
31
32 bool can_convert(const BasicTypeDeclaration &from, const BasicTypeDeclaration &to)
33 {
34         if(from.kind==BasicTypeDeclaration::INT && to.kind==BasicTypeDeclaration::FLOAT)
35                 return from.size<=to.size;
36         else if(from.kind!=to.kind)
37                 return false;
38         else if(from.kind==BasicTypeDeclaration::INT && from.sign!=to.sign)
39                 return from.sign && from.size<=to.size;
40         else if(is_vector_or_matrix(from) && from.size==to.size)
41         {
42                 BasicTypeDeclaration *from_base = dynamic_cast<BasicTypeDeclaration *>(from.base_type);
43                 BasicTypeDeclaration *to_base = dynamic_cast<BasicTypeDeclaration *>(to.base_type);
44                 return (from_base && to_base && can_convert(*from_base, *to_base));
45         }
46         else
47                 return false;
48 }
49
50
51 unsigned TypeComparer::next_tag = 1;
52
53 void TypeComparer::compare(Node &node1, Node &node2)
54 {
55         if(&node1==&node2)
56                 r_result = true;
57         else
58         {
59                 second = &node2;
60                 node1.visit(*this);
61         }
62 }
63
64 template<typename T>
65 T *TypeComparer::multi_visit(T &node)
66 {
67         static unsigned tag = next_tag++;
68
69         if(second)
70         {
71                 Node *s = second;
72                 first = &node;
73                 first_tag = tag;
74                 second = 0;
75                 s->visit(*this);
76         }
77         else if(!first || tag!=first_tag)
78                 r_result = false;
79         else
80         {
81                 T *f = static_cast<T *>(first);
82                 first = 0;
83                 return f;
84         }
85
86         return 0;
87 }
88
89 void TypeComparer::visit(Literal &literal)
90 {
91         if(Literal *lit1 = multi_visit(literal))
92         {
93                 if(!lit1->type || !literal.type)
94                         r_result = false;
95                 else
96                 {
97                         compare(*lit1->type, *literal.type);
98                         if(r_result)
99                                 r_result = (literal.value.check_type<int>() && lit1->value.value<int>()==literal.value.value<int>());
100                 }
101         }
102 }
103
104 void TypeComparer::visit(VariableReference &var)
105 {
106         if(VariableReference *var1 = multi_visit(var))
107         {
108                 if(!var1->declaration || !var.declaration)
109                         r_result = false;
110                 else if(!var1->declaration->constant || !var.declaration->constant)
111                         r_result = false;
112                 else if(!var1->declaration->init_expression || !var.declaration->init_expression)
113                         r_result = false;
114                 else
115                         compare(*var1->declaration->init_expression, *var.declaration->init_expression);
116         }
117 }
118
119 void TypeComparer::visit(UnaryExpression &unary)
120 {
121         if(UnaryExpression *unary1 = multi_visit(unary))
122         {
123                 if(unary1->oper!=unary.oper)
124                         r_result = false;
125                 else
126                         compare(*unary1->expression, *unary.expression);
127         }
128 }
129
130 void TypeComparer::visit(BinaryExpression &binary)
131 {
132         if(BinaryExpression *binary1 = multi_visit(binary))
133         {
134                 if(binary1->oper!=binary.oper)
135                         r_result = false;
136                 else
137                 {
138                         compare(*binary1->left, *binary.left);
139                         if(r_result)
140                                 compare(*binary1->right, *binary.right);
141                 }
142         }
143 }
144
145 void TypeComparer::visit(TernaryExpression &ternary)
146 {
147         if(TernaryExpression *ternary1 = multi_visit(ternary))
148         {
149                 if(ternary1->oper!=ternary.oper)
150                         r_result = false;
151                 else
152                 {
153                         compare(*ternary1->condition, *ternary.condition);
154                         if(r_result)
155                                 compare(*ternary1->true_expr, *ternary.true_expr);
156                         if(r_result)
157                                 compare(*ternary1->false_expr, *ternary.false_expr);
158                 }
159         }
160 }
161
162 void TypeComparer::visit(BasicTypeDeclaration &basic)
163 {
164         if(BasicTypeDeclaration *basic1 = multi_visit(basic))
165         {
166                 if(basic1->kind!=basic.kind || basic1->size!=basic.size || basic1->sign!=basic.sign)
167                         r_result = false;
168                 else if(basic1->base_type && basic.base_type)
169                         compare(*basic1->base_type, *basic.base_type);
170                 else
171                         r_result = (!basic1->base_type && !basic.base_type);
172         }
173 }
174
175 void TypeComparer::visit(ImageTypeDeclaration &image)
176 {
177         if(ImageTypeDeclaration *image1 = multi_visit(image))
178         {
179                 if(image1->dimensions!=image.dimensions || image1->array!=image.array)
180                         r_result = false;
181                 else if(image1->sampled!=image.sampled || image1->shadow!=image.shadow || image1->multisample!=image.multisample)
182                         r_result = false;
183                 else if(image1->format!=image.format)
184                         r_result = false;
185                 else if(image1->base_type && image.base_type)
186                         compare(*image1->base_type, *image.base_type);
187                 else
188                         r_result = (!image1->base_type && !image.base_type);
189         }
190 }
191
192 void TypeComparer::visit(StructDeclaration &strct)
193 {
194         if(StructDeclaration *strct1 = multi_visit(strct))
195         {
196                 if(strct1->members.body.size()!=strct.members.body.size())
197                         r_result = false;
198                 else
199                 {
200                         r_result = true;
201                         auto i = strct1->members.body.begin();
202                         auto j = strct.members.body.begin();
203                         for(; (r_result && i!=strct1->members.body.end()); ++i, ++j)
204                                 compare(**i, **j);
205                 }
206         }
207 }
208
209 void TypeComparer::visit(VariableDeclaration &var)
210 {
211         if(VariableDeclaration *var1 = multi_visit(var))
212         {
213                 if(var1->name!=var.name || var1->array!=var.array)
214                         r_result = false;
215                 else if(!var1->type_declaration || !var.type_declaration)
216                         r_result = false;
217                 else
218                 {
219                         if(var1->array)
220                         {
221                                 r_result = false;
222                                 if(var1->array_size && var.array_size)
223                                         compare(*var1->array_size, *var.array_size);
224                                 else if(!var1->array_size && !var.array_size)
225                                         r_result = true;
226                         }
227                         if(r_result && var1->type_declaration!=var.type_declaration)
228                                 compare(*var1->type_declaration, *var.type_declaration);
229                         // TODO Compare layout qualifiers for interface block members
230                 }
231         }
232 }
233
234
235 void LocationCounter::visit(BasicTypeDeclaration &basic)
236 {
237         r_count = basic.kind==BasicTypeDeclaration::MATRIX ? basic.size>>16 : 1;
238 }
239
240 void LocationCounter::visit(ImageTypeDeclaration &)
241 {
242         r_count = 1;
243 }
244
245 void LocationCounter::visit(StructDeclaration &strct)
246 {
247         unsigned total = 0;
248         for(const RefPtr<Statement> &s: strct.members.body)
249         {
250                 r_count = 1;
251                 s->visit(*this);
252                 total += r_count;
253         }
254         r_count = total;
255 }
256
257 void LocationCounter::visit(VariableDeclaration &var)
258 {
259         r_count = 1;
260         if(var.type_declaration)
261                 var.type_declaration->visit(*this);
262         if(var.array)
263                 if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
264                         if(literal->value.check_type<int>())
265                                 r_count *= literal->value.value<int>();
266 }
267
268
269 void MemoryRequirementsCalculator::visit(BasicTypeDeclaration &basic)
270 {
271         if(basic.kind==BasicTypeDeclaration::BOOL)
272         {
273                 r_size = 1;
274                 r_alignment = 1;
275         }
276         else if(basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT)
277         {
278                 r_size = basic.size/8;
279                 r_alignment = r_size;
280         }
281         else if(basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX)
282         {
283                 basic.base_type->visit(*this);
284                 unsigned n_elem = basic.size&0xFFFF;
285                 r_size *= n_elem;
286                 if(basic.kind==BasicTypeDeclaration::VECTOR)
287                         r_alignment *= (n_elem==3 ? 4 : n_elem);
288         }
289         else if(basic.kind==BasicTypeDeclaration::ARRAY)
290                 basic.base_type->visit(*this);
291
292         if(basic.extended_alignment)
293                 r_alignment = (r_alignment+15)&~15U;
294 }
295
296 void MemoryRequirementsCalculator::visit(StructDeclaration &strct)
297 {
298         unsigned total = 0;
299         unsigned max_align = 1;
300         for(const RefPtr<Statement> &s: strct.members.body)
301         {
302                 r_size = 0;
303                 r_alignment = 1;
304                 r_offset = -1;
305                 s->visit(*this);
306                 if(r_offset>=0)
307                         total = r_offset;
308                 total += r_alignment-1;
309                 total -= total%r_alignment;
310                 total += r_size;
311                 max_align = max(max_align, r_alignment);
312         }
313         r_size = total;
314         r_alignment = max_align;
315         if(strct.extended_alignment)
316                 r_alignment = (r_alignment+15)&~15U;
317         r_size += r_alignment-1;
318         r_size -= r_size%r_alignment;
319 }
320
321 void MemoryRequirementsCalculator::visit(VariableDeclaration &var)
322 {
323         r_offset = get_layout_value(var.layout.get(), "offset");
324
325         if(var.type_declaration)
326                 var.type_declaration->visit(*this);
327         if(var.array)
328                 if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
329                         if(literal->value.check_type<int>())
330                         {
331                                 unsigned aligned_size = r_size+r_alignment-1;
332                                 aligned_size -= aligned_size%r_alignment;
333                                 r_size = aligned_size*literal->value.value<int>();
334                         }
335 }
336
337
338 set<Node *> DependencyCollector::apply(FunctionDeclaration &func)
339 {
340         func.visit(*this);
341         return dependencies;
342 }
343
344 void DependencyCollector::visit(VariableReference &var)
345 {
346         if(var.declaration && !locals.count(var.declaration))
347         {
348                 dependencies.insert(var.declaration);
349                 var.declaration->visit(*this);
350         }
351 }
352
353 void DependencyCollector::visit(FunctionCall &call)
354 {
355         if(call.declaration)
356         {
357                 dependencies.insert(call.declaration);
358                 if(call.declaration->definition)
359                         call.declaration->definition->visit(*this);
360         }
361         TraversingVisitor::visit(call);
362 }
363
364 void DependencyCollector::visit(VariableDeclaration &var)
365 {
366         locals.insert(&var);
367         if(var.type_declaration)
368         {
369                 dependencies.insert(var.type_declaration);
370                 var.type_declaration->visit(*this);
371         }
372
373         TraversingVisitor::visit(var);
374 }
375
376 void DependencyCollector::visit(FunctionDeclaration &func)
377 {
378         if(!visited_functions.count(&func))
379         {
380                 visited_functions.insert(&func);
381                 TraversingVisitor::visit(func);
382         }
383 }
384
385
386 set<Node *> AssignmentCollector::apply(Node &node)
387 {
388         node.visit(*this);
389         return assigned_variables;
390 }
391
392 void AssignmentCollector::visit(VariableReference &var)
393 {
394         if(assignment_target)
395                 assigned_variables.insert(var.declaration);
396 }
397
398 void AssignmentCollector::visit(UnaryExpression &unary)
399 {
400         SetFlag set_assignment(assignment_target, (unary.oper->token[1]=='+' || unary.oper->token[1]=='-'));
401         TraversingVisitor::visit(unary);
402 }
403
404 void AssignmentCollector::visit(BinaryExpression &binary)
405 {
406         binary.left->visit(*this);
407         SetFlag clear_assignment(assignment_target, false);
408         binary.right->visit(*this);
409 }
410
411 void AssignmentCollector::visit(Assignment &assign)
412 {
413         {
414                 SetFlag set_assignment(assignment_target);
415                 assign.left->visit(*this);
416         }
417         assign.right->visit(*this);
418 }
419
420 } // namespace SL
421 } // namespace GL
422 } // namespace Msp