]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/reflect.cpp
Split the Light class into subclasses by light type
[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(BasicTypeDeclaration &basic)
126 {
127         if(BasicTypeDeclaration *basic1 = multi_visit(basic))
128         {
129                 if(basic1->kind!=basic.kind || basic1->size!=basic.size || basic1->sign!=basic.sign)
130                         r_result = false;
131                 else if(basic1->base_type && basic.base_type)
132                         compare(*basic1->base_type, *basic.base_type);
133                 else
134                         r_result = (!basic1->base_type && !basic.base_type);
135         }
136 }
137
138 void TypeComparer::visit(ImageTypeDeclaration &image)
139 {
140         if(ImageTypeDeclaration *image1 = multi_visit(image))
141         {
142                 if(image1->dimensions!=image.dimensions || image1->array!=image.array)
143                         r_result = false;
144                 else if(image1->sampled!=image.sampled || image1->shadow!=image.shadow)
145                         r_result = false;
146                 else if(image1->base_type && image.base_type)
147                         compare(*image1->base_type, *image.base_type);
148                 else
149                         r_result = (!image1->base_type && !image.base_type);
150         }
151 }
152
153 void TypeComparer::visit(StructDeclaration &strct)
154 {
155         if(StructDeclaration *strct1 = multi_visit(strct))
156         {
157                 if(strct1->members.body.size()!=strct.members.body.size())
158                         r_result = false;
159                 else
160                 {
161                         r_result = true;
162                         auto i = strct1->members.body.begin();
163                         auto j = strct.members.body.begin();
164                         for(; (r_result && i!=strct1->members.body.end()); ++i, ++j)
165                                 compare(**i, **j);
166                 }
167         }
168 }
169
170 void TypeComparer::visit(VariableDeclaration &var)
171 {
172         if(VariableDeclaration *var1 = multi_visit(var))
173         {
174                 if(var1->name!=var.name || var1->array!=var.array)
175                         r_result = false;
176                 else if(!var1->type_declaration || !var.type_declaration)
177                         r_result = false;
178                 else
179                 {
180                         if(var1->array)
181                         {
182                                 r_result = false;
183                                 if(var1->array_size && var.array_size)
184                                         compare(*var1->array_size, *var.array_size);
185                         }
186                         if(r_result && var1->type_declaration!=var.type_declaration)
187                                 compare(*var1->type_declaration, *var.type_declaration);
188                         // TODO Compare layout qualifiers for interface block members
189                 }
190         }
191 }
192
193
194 LocationCounter::LocationCounter():
195         r_count(0)
196 { }
197
198 void LocationCounter::visit(BasicTypeDeclaration &basic)
199 {
200         r_count = basic.kind==BasicTypeDeclaration::MATRIX ? basic.size>>16 : 1;
201 }
202
203 void LocationCounter::visit(ImageTypeDeclaration &)
204 {
205         r_count = 1;
206 }
207
208 void LocationCounter::visit(StructDeclaration &strct)
209 {
210         unsigned total = 0;
211         for(const RefPtr<Statement> &s: strct.members.body)
212         {
213                 r_count = 1;
214                 s->visit(*this);
215                 total += r_count;
216         }
217         r_count = total;
218 }
219
220 void LocationCounter::visit(VariableDeclaration &var)
221 {
222         r_count = 1;
223         if(var.type_declaration)
224                 var.type_declaration->visit(*this);
225         if(var.array)
226                 if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
227                         if(literal->value.check_type<int>())
228                                 r_count *= literal->value.value<int>();
229 }
230
231
232 void MemoryRequirementsCalculator::visit(BasicTypeDeclaration &basic)
233 {
234         if(basic.kind==BasicTypeDeclaration::BOOL)
235         {
236                 r_size = 1;
237                 r_alignment = 1;
238         }
239         else if(basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT)
240         {
241                 r_size = basic.size/8;
242                 r_alignment = r_size;
243         }
244         else if(basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX)
245         {
246                 basic.base_type->visit(*this);
247                 unsigned n_elem = basic.size&0xFFFF;
248                 r_size *= n_elem;
249                 if(basic.kind==BasicTypeDeclaration::VECTOR)
250                         r_alignment *= (n_elem==3 ? 4 : n_elem);
251         }
252         else if(basic.kind==BasicTypeDeclaration::ARRAY)
253                 basic.base_type->visit(*this);
254 }
255
256 void MemoryRequirementsCalculator::visit(StructDeclaration &strct)
257 {
258         unsigned total = 0;
259         unsigned max_align = 1;
260         for(const RefPtr<Statement> &s: strct.members.body)
261         {
262                 r_size = 0;
263                 r_alignment = 1;
264                 r_offset = -1;
265                 s->visit(*this);
266                 if(r_offset)
267                         total = r_offset;
268                 total += r_alignment-1;
269                 total -= total%r_alignment;
270                 total += r_size;
271                 max_align = max(max_align, r_alignment);
272         }
273         r_size = total;
274         r_alignment = max_align;
275 }
276
277 void MemoryRequirementsCalculator::visit(VariableDeclaration &var)
278 {
279         if(var.layout)
280         {
281                 auto i = find_member(var.layout->qualifiers, string("offset"), &Layout::Qualifier::name);
282                 if(i!=var.layout->qualifiers.end())
283                         r_offset = i->value;
284         }
285
286         if(var.type_declaration)
287                 var.type_declaration->visit(*this);
288         if(var.array)
289                 if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
290                         if(literal->value.check_type<int>())
291                                 r_size += r_alignment*(literal->value.value<int>()-1);
292 }
293
294
295 set<Node *> DependencyCollector::apply(FunctionDeclaration &func)
296 {
297         func.visit(*this);
298         return dependencies;
299 }
300
301 void DependencyCollector::visit(VariableReference &var)
302 {
303         if(var.declaration && !locals.count(var.declaration))
304         {
305                 dependencies.insert(var.declaration);
306                 var.declaration->visit(*this);
307         }
308 }
309
310 void DependencyCollector::visit(InterfaceBlockReference &iface)
311 {
312         if(iface.declaration)
313         {
314                 dependencies.insert(iface.declaration);
315                 iface.declaration->visit(*this);
316         }
317 }
318
319 void DependencyCollector::visit(FunctionCall &call)
320 {
321         if(call.declaration)
322         {
323                 dependencies.insert(call.declaration);
324                 if(call.declaration->definition)
325                         call.declaration->definition->visit(*this);
326         }
327         TraversingVisitor::visit(call);
328 }
329
330 void DependencyCollector::visit(VariableDeclaration &var)
331 {
332         locals.insert(&var);
333         if(var.type_declaration)
334         {
335                 dependencies.insert(var.type_declaration);
336                 var.type_declaration->visit(*this);
337         }
338
339         TraversingVisitor::visit(var);
340 }
341
342 void DependencyCollector::visit(FunctionDeclaration &func)
343 {
344         if(!visited_functions.count(&func))
345         {
346                 visited_functions.insert(&func);
347                 TraversingVisitor::visit(func);
348         }
349 }
350
351 } // namespace SL
352 } // namespace GL
353 } // namespace Msp