]> git.tdb.fi Git - gldbg.git/blob - genwrap.py
Track vertex array state
[gldbg.git] / genwrap.py
1 #!/usr/bin/python
2 # $Id$
3
4 import sys
5 import os
6
7 class InputFile:
8         def __init__(self, fn):
9                 self.file = open(fn)
10
11         def __iter__(self):
12                 for l in self.file:
13                         h = l.find("#")
14                         if h==0 or (h>0 and l[h-1].isspace()):
15                                 l = l[:h]
16
17                         l = l.rstrip()
18                         if not l:
19                                 continue
20
21                         yield l
22                 
23
24 def strip_name(name):
25         """Strips any vendor suffix and GL prefix from a name (but not GLX prefix)"""
26
27         suffix = ""
28         if name.endswith(" *"):
29                 suffix = " *"
30                 name = name[:-2]
31         elif name.endswith("Pointer"):
32                 suffix = "Pointer"
33                 name = name[:-7]
34
35         prefix = ""
36         if name.startswith("const "):
37                 prefix = "const "
38                 name = name[6:]
39
40         if name.startswith("GL") and not name.startswith("GLX"):
41                 name = name[2:]
42         if name.endswith(("EXT", "ARB", "SGI", "IBM", "ATI")):
43                 return prefix+name[:-3]+suffix
44         elif name.endswith("SGIX"):
45                 return prefix+name[:-4]+suffix
46         elif name.endswith(("NV", "HP")):
47                 return prefix+name[:-2]+suffix
48         else:
49                 return prefix+name+suffix
50
51
52 class Typemap:
53         def __init__(self, fn):
54                 self.map = {}
55                 for line in InputFile(fn):
56                         parts = [p.strip() for p in line.split(',')]
57                         if parts[3]=="*":
58                                 parts[3] = parts[0]
59                         elif parts[3][-1]=='*' and parts[3][-2]!=' ':
60                                 parts[3] = parts[3][:-1]+" *"
61                         self.map[tuple(parts[0:3])] = tuple(parts[3:6])
62
63         def wildcard_match(self, a, b):
64                 if a=="*" or b=="*":
65                         return True
66                 return a==b
67
68         def __getitem__(self, key):
69                 try:
70                         return self.map[(key[0], "*", "*")]
71                 except KeyError:
72                         for k, v in self.map.iteritems():
73                                 if strip_name(k[0])==strip_name(key[0]) and self.wildcard_match(k[1], key[1]) and self.wildcard_match(k[2], key[2]):
74                                         return v
75                         raise KeyError, key
76
77         def update(self, other):
78                 self.map.update(other.map)
79
80
81 class IOmap:
82         def __init__(self, fn):
83                 self.map = {}
84                 self.map["void"] = None
85                 for line in InputFile(fn):
86                         parts = [p.strip() for p in line.split(',')]
87                         self.map[parts[0]] = tuple(parts[1:])
88
89         def __getitem__(self, key):
90                 return self.map[strip_name(key)]
91
92
93 class Function:
94         class Parameter:
95                 def __init__(self, func, name):
96                         self.func = func
97                         self.name = name
98                         self.type = None
99                         self.direction = "in"
100                         self.kind = "value"
101                         self.size = None
102                         self.ctype = None
103                         self.csize = None
104                         self.io = None
105
106                 def set_type(self, type, dir, kind):
107                         self.type = type
108                         self.direction = dir
109                         self.kind = kind
110
111                 def set_size(self, size):
112                         if type(size)==str and size.isdigit():
113                                 self.size = int(size)
114                         else:
115                                 self.size = size
116
117                 def derive_ctype(self):
118                         m = typemap[(self.type, self.direction, self.kind)]
119                         self.ctype = m[0]
120                         if m[1]!="*":
121                                 self.direction = m[1]
122                         if m[2]!="*":
123                                 self.kind = m[2]
124                         self.base_ctype = self.ctype
125                         if self.kind=="value":
126                                 if self.base_ctype.startswith("const "):
127                                         self.base_ctype = self.base_ctype[6:]
128                         else:
129                                 if self.direction=="in":
130                                         self.ctype = "const "+self.ctype
131                                 self.ctype = self.ctype+" *"
132                         self.io = iomap[self.base_ctype]
133
134                 def derive_csize(self):
135                         if self.kind=="array" and self.size is not None:
136                                 self.csize = None
137                                 if type(self.size)==int:
138                                         self.csize = "%d*sizeof(%s)"%(self.size, self.base_ctype)
139                                 elif self.size.startswith("COMPSIZE("):
140                                         self.csize = self.func.compsize(self.size[9:-1], self.base_ctype)
141                                 elif self.size=="pname":
142                                         self.csize = "paramsize(pname)*sizeof(%s)"%self.base_ctype
143                                 else:
144                                         s = self.func.get_param(self.size.split('*')[0])
145                                         if (s.type=="SizeI" or s.type.endswith("Int32") or s.type.startswith("BufferSize")):
146                                                 if s.kind=="value":
147                                                         self.csize = "%s"%self.size
148                                                         if self.func.name.startswith("glUniformMatrix") and self.func.name[16]!='x':
149                                                                 self.csize += "*%d"%(int(self.func.name[15])**2)
150                                                         elif self.func.name.startswith("glUniform") and self.func.name[9].isdigit():
151                                                                 self.csize += "*%s"%self.func.name[9]
152                                                         if strip_name(self.base_ctype)!="void":
153                                                                 self.csize += "*sizeof(%s)"%self.base_ctype
154                                                 elif s.kind=="array" and s.size==1:
155                                                         self.csize = "*%s"%s.name
156                                         if not self.csize:
157                                                 sys.stderr.write("Could not determine size for array parameter '%s[%s]' of function '%s'\n"%(self.name, self.size, self.func.name))
158                         elif self.kind=="reference":
159                                 self.csize = "sizeof(%s)"%self.base_ctype
160
161         def __init__(self, name, pnames):
162                 self.name = name
163                 self.ret = Function.Parameter(self, "ret")
164                 self.params = [Function.Parameter(self, n) for n in pnames]
165                 self.category = None
166
167         def get_param(self, pname):
168                 for p in self.params:
169                         if p.name==pname:
170                                 return p
171                 raise KeyError, pname
172
173         def set_category(self, cat):
174                 self.category = cat
175
176         def compsize(self, size, btype):
177                 if not size:
178                         return
179
180                 res = ""
181                 have_type = False
182                 for c in size.replace(',', '/').split('/'):
183                         param = self.get_param(c)
184                         if not param:
185                                 sys.stderr.write("Compsize '%s' for function '%s' failed: No parameter '%s'\n"%(size, self.name, c))
186                                 return
187
188                         if res:
189                                 res += "*"
190
191                         cn = strip_name(param.type)
192                         if cn.endswith("Type"):
193                                 res += "typesize(%s)"%param.name
194                                 have_type = True
195                         elif cn.endswith("Format"):
196                                 res += "formatsize(%s)"%param.name
197                         elif param.name=="pname" or cn.endswith("Parameter") or (param.name=="target" and cn=="enum"):
198                                 res += "paramsize(%s)"%param.name
199                         elif param.name=="buffer" and cn=="enum":
200                                 res += "buffersize(%s)"%param.name
201                         elif (cn=="SizeI" or cn.endswith("Int32")) and not param.size:
202                                 res += param.name
203                         else:
204                                 sys.stderr.write("Compsize '%s' for function '%s' failed: Parameter '%s' has unknown type '%s'\n"%(size, self.name, param.name, param.type))
205                                 return
206                 if not have_type:
207                         res += "*sizeof(%s)"%btype
208                 return res
209
210         def finalize(self):
211                 self.ret.derive_ctype()
212                 for p in self.params:
213                         p.derive_ctype()
214                 for p in self.params:
215                         p.derive_csize()
216
217
218 class Template:
219         def __init__(self, fn):
220                 self.sections = []
221                 self.handcode = []
222
223                 literal = True
224                 text = ""
225                 for line in InputFile(fn):
226                         if line[0]==':':
227                                 if not literal and text:
228                                         self.add_section(text, literal)
229                                         text = ""
230                                 text += line[1:]+"\n"
231                                 literal = True
232                         elif line[0]=='!':
233                                 parts = line[1:].split()
234                                 if parts[0]=="handcode":
235                                         self.handcode.append(parts[1])
236                         else:
237                                 if literal and text:
238                                         self.add_section(text, literal)
239                                         text = ""
240                                 text += line+"\n"
241                                 literal = False
242                 if text:
243                         self.add_section(text, literal)
244
245         def add_section(self, text, literal):
246                 if literal:
247                         self.sections.append(text)
248                 else:
249                         self.sections.append(compile(text, "-", "exec"))
250
251         def write(self, str, *args):
252                 sys.stdout.write(str%args)
253
254         def writeln(self, str, *args):
255                 sys.stdout.write(str%args+"\n")
256
257         def process(self, functions):
258                 for sect in self.sections:
259                         if type(sect)==str:
260                                 print sect
261                         else:
262                                 for func in functions:
263                                         if func.name in self.handcode:
264                                                 continue
265                                         globals = {
266                                                 "w": self.write,
267                                                 "wl": self.writeln,
268                                                 "func": func,
269                                                 "ret": func.ret,
270                                                 "params": func.params
271                                         }
272                                         eval(sect, globals)
273
274
275 class Files:
276         def __init__(self, fn):
277                 self.typemap = None
278                 self.iomap = None
279                 self.specs = []
280                 self.prefix = None
281                 self.ignore_categs = []
282                 self.ignore_funcs = []
283
284                 for line in InputFile(fn):
285                         parts = line.split()
286                         if parts[0]=="typemap":
287                                 self.typemap = parts[1]
288                         elif parts[0]=="iomap":
289                                 self.iomap = parts[1]
290                         elif parts[0]=="spec":
291                                 self.specs.append(parts[1])
292                         elif parts[0]=="prefix":
293                                 self.prefix = parts[1]
294                         elif parts[0]=="ignore":
295                                 if parts[1]=="category":
296                                         self.ignore_categs.append(parts[2])
297                                 elif parts[1]=="function":
298                                         self.ignore_funcs.append(parts[2])
299                         else:
300                                 sys.stderr.write("Unknown keyword '%s'\n", parts[0])
301
302
303 def read_spec(fn, prefix):
304         funcs = []
305         cur_func = None
306         for line in InputFile(fn):
307                 if line.find(':')>=0:
308                         continue
309                 elif line[0]=='\t' and cur_func:
310                         parts = line.split()
311                         if parts[0]=="return":
312                                 cur_func.ret.set_type(parts[1], "out", "value")
313                         elif parts[0]=="param":
314                                 bracket = parts[4].find('[')
315                                 if bracket>=0:
316                                         parts.insert(5, parts[4][bracket:])
317                                         parts[4] = parts[4][:bracket]
318
319                                 param = cur_func.get_param(parts[1])
320                                 param.set_type(parts[2], parts[3], parts[4])
321                                 if len(parts)==6 or (len(parts)>6 and parts[6]!="retained"):
322                                         param.set_size(parts[5][1:-1])
323                         elif parts[0]=="category":
324                                 cur_func.set_category(parts[1])
325                         elif parts[0]=="glxvendorglx" and cur_func.category=="glx":
326                                 cur_func.set_category("glxext")
327                 else:
328                         paren = line.find('(')
329                         if paren>0:
330                                 cparen = line.rfind(')')
331                                 if cparen>paren+1:
332                                         pnames = [n.strip() for n in line[paren+1:cparen].split(",")]
333                                 else:
334                                         pnames = []
335                                 cur_func = Function(prefix+line[:paren], pnames)
336                                 funcs.append(cur_func)
337         return funcs
338
339 template = Template(sys.argv[1])
340 functions = []
341 for i in sys.argv[2:]:
342         files = Files(i)
343
344         typemap = Typemap(files.typemap)
345         iomap = IOmap(files.iomap)
346         for s in files.specs:
347                 funcs = read_spec(s, files.prefix)
348                 funcs = [f for f in funcs if f.name not in files.ignore_funcs and f.category not in files.ignore_categs]
349                 for f in funcs:
350                         f.finalize()
351                 names = [f.name for f in funcs]
352                 functions = [f for f in functions if f.name not in names]+funcs
353
354 template.process(functions)