]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/reflect.cpp
Check the flat qualifier from the correct member
[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)
182                         r_result = false;
183                 else if(image1->base_type && image.base_type)
184                         compare(*image1->base_type, *image.base_type);
185                 else
186                         r_result = (!image1->base_type && !image.base_type);
187         }
188 }
189
190 void TypeComparer::visit(StructDeclaration &strct)
191 {
192         if(StructDeclaration *strct1 = multi_visit(strct))
193         {
194                 if(strct1->members.body.size()!=strct.members.body.size())
195                         r_result = false;
196                 else
197                 {
198                         r_result = true;
199                         auto i = strct1->members.body.begin();
200                         auto j = strct.members.body.begin();
201                         for(; (r_result && i!=strct1->members.body.end()); ++i, ++j)
202                                 compare(**i, **j);
203                 }
204         }
205 }
206
207 void TypeComparer::visit(VariableDeclaration &var)
208 {
209         if(VariableDeclaration *var1 = multi_visit(var))
210         {
211                 if(var1->name!=var.name || var1->array!=var.array)
212                         r_result = false;
213                 else if(!var1->type_declaration || !var.type_declaration)
214                         r_result = false;
215                 else
216                 {
217                         if(var1->array)
218                         {
219                                 r_result = false;
220                                 if(var1->array_size && var.array_size)
221                                         compare(*var1->array_size, *var.array_size);
222                                 else if(!var1->array_size && !var.array_size)
223                                         r_result = true;
224                         }
225                         if(r_result && var1->type_declaration!=var.type_declaration)
226                                 compare(*var1->type_declaration, *var.type_declaration);
227                         // TODO Compare layout qualifiers for interface block members
228                 }
229         }
230 }
231
232
233 void LocationCounter::visit(BasicTypeDeclaration &basic)
234 {
235         r_count = basic.kind==BasicTypeDeclaration::MATRIX ? basic.size>>16 : 1;
236 }
237
238 void LocationCounter::visit(ImageTypeDeclaration &)
239 {
240         r_count = 1;
241 }
242
243 void LocationCounter::visit(StructDeclaration &strct)
244 {
245         unsigned total = 0;
246         for(const RefPtr<Statement> &s: strct.members.body)
247         {
248                 r_count = 1;
249                 s->visit(*this);
250                 total += r_count;
251         }
252         r_count = total;
253 }
254
255 void LocationCounter::visit(VariableDeclaration &var)
256 {
257         r_count = 1;
258         if(var.type_declaration)
259                 var.type_declaration->visit(*this);
260         if(var.array)
261                 if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
262                         if(literal->value.check_type<int>())
263                                 r_count *= literal->value.value<int>();
264 }
265
266
267 void MemoryRequirementsCalculator::visit(BasicTypeDeclaration &basic)
268 {
269         if(basic.kind==BasicTypeDeclaration::BOOL)
270         {
271                 r_size = 1;
272                 r_alignment = 1;
273         }
274         else if(basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT)
275         {
276                 r_size = basic.size/8;
277                 r_alignment = r_size;
278         }
279         else if(basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX)
280         {
281                 basic.base_type->visit(*this);
282                 unsigned n_elem = basic.size&0xFFFF;
283                 r_size *= n_elem;
284                 if(basic.kind==BasicTypeDeclaration::VECTOR)
285                         r_alignment *= (n_elem==3 ? 4 : n_elem);
286         }
287         else if(basic.kind==BasicTypeDeclaration::ARRAY)
288                 basic.base_type->visit(*this);
289
290         if(basic.extended_alignment)
291                 r_alignment = (r_alignment+15)&~15U;
292 }
293
294 void MemoryRequirementsCalculator::visit(StructDeclaration &strct)
295 {
296         unsigned total = 0;
297         unsigned max_align = 1;
298         for(const RefPtr<Statement> &s: strct.members.body)
299         {
300                 r_size = 0;
301                 r_alignment = 1;
302                 r_offset = -1;
303                 s->visit(*this);
304                 if(r_offset>=0)
305                         total = r_offset;
306                 total += r_alignment-1;
307                 total -= total%r_alignment;
308                 total += r_size;
309                 max_align = max(max_align, r_alignment);
310         }
311         r_size = total;
312         r_alignment = max_align;
313         if(strct.extended_alignment)
314                 r_alignment = (r_alignment+15)&~15U;
315         r_size += r_alignment-1;
316         r_size -= r_size%r_alignment;
317 }
318
319 void MemoryRequirementsCalculator::visit(VariableDeclaration &var)
320 {
321         r_offset = get_layout_value(var.layout.get(), "offset");
322
323         if(var.type_declaration)
324                 var.type_declaration->visit(*this);
325         if(var.array)
326                 if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
327                         if(literal->value.check_type<int>())
328                         {
329                                 unsigned aligned_size = r_size+r_alignment-1;
330                                 aligned_size -= aligned_size%r_alignment;
331                                 r_size = aligned_size*literal->value.value<int>();
332                         }
333 }
334
335
336 set<Node *> DependencyCollector::apply(FunctionDeclaration &func)
337 {
338         func.visit(*this);
339         return dependencies;
340 }
341
342 void DependencyCollector::visit(VariableReference &var)
343 {
344         if(var.declaration && !locals.count(var.declaration))
345         {
346                 dependencies.insert(var.declaration);
347                 var.declaration->visit(*this);
348         }
349 }
350
351 void DependencyCollector::visit(FunctionCall &call)
352 {
353         if(call.declaration)
354         {
355                 dependencies.insert(call.declaration);
356                 if(call.declaration->definition)
357                         call.declaration->definition->visit(*this);
358         }
359         TraversingVisitor::visit(call);
360 }
361
362 void DependencyCollector::visit(VariableDeclaration &var)
363 {
364         locals.insert(&var);
365         if(var.type_declaration)
366         {
367                 dependencies.insert(var.type_declaration);
368                 var.type_declaration->visit(*this);
369         }
370
371         TraversingVisitor::visit(var);
372 }
373
374 void DependencyCollector::visit(FunctionDeclaration &func)
375 {
376         if(!visited_functions.count(&func))
377         {
378                 visited_functions.insert(&func);
379                 TraversingVisitor::visit(func);
380         }
381 }
382
383
384 set<Node *> AssignmentCollector::apply(Node &node)
385 {
386         node.visit(*this);
387         return assigned_variables;
388 }
389
390 void AssignmentCollector::visit(VariableReference &var)
391 {
392         if(assignment_target)
393                 assigned_variables.insert(var.declaration);
394 }
395
396 void AssignmentCollector::visit(UnaryExpression &unary)
397 {
398         SetFlag set_assignment(assignment_target, (unary.oper->token[1]=='+' || unary.oper->token[1]=='-'));
399         TraversingVisitor::visit(unary);
400 }
401
402 void AssignmentCollector::visit(BinaryExpression &binary)
403 {
404         binary.left->visit(*this);
405         SetFlag clear_assignment(assignment_target, false);
406         binary.right->visit(*this);
407 }
408
409 void AssignmentCollector::visit(Assignment &assign)
410 {
411         {
412                 SetFlag set_assignment(assignment_target);
413                 assign.left->visit(*this);
414         }
415         assign.right->visit(*this);
416 }
417
418 } // namespace SL
419 } // namespace GL
420 } // namespace Msp