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