Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | #!/usr/bin/python3 |
2 | # | |
3 | # python script to generate cdecl to stdcall wrappers for GL functions | |
4 | # adapted from genheaders.py | |
5 | # | |
6 | # Copyright (c) 2013 The Khronos Group Inc. | |
7 | # | |
8 | # Permission is hereby granted, free of charge, to any person obtaining a | |
9 | # copy of this software and/or associated documentation files (the | |
10 | # "Materials"), to deal in the Materials without restriction, including | |
11 | # without limitation the rights to use, copy, modify, merge, publish, | |
12 | # distribute, sublicense, and/or sell copies of the Materials, and to | |
13 | # permit persons to whom the Materials are furnished to do so, subject to | |
14 | # the following conditions: | |
15 | # | |
16 | # The above copyright notice and this permission notice shall be included | |
17 | # in all copies or substantial portions of the Materials. | |
18 | # | |
19 | # THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
20 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
21 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
22 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
23 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
24 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
25 | # MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. | |
26 | ||
27 | import sys, time, pdb, string, cProfile | |
28 | from reg import * | |
29 | ||
30 | # Default input / log files | |
31 | errFilename = None | |
32 | diagFilename = 'diag.txt' | |
33 | regFilename = 'gl.xml' | |
34 | outFilename = 'gen_gl_wrappers.c' | |
35 | ||
36 | protect=True | |
37 | prefix="gl" | |
38 | preresolve=False | |
39 | wrapper=False | |
40 | shim=False | |
41 | thunk=False | |
42 | thunkdefs=False | |
43 | staticwrappers=False | |
44 | nodebug=False | |
45 | ||
46 | #exclude base WGL API | |
47 | WinGDI={key: 1 for key in [ | |
48 | "wglCopyContext" | |
49 | ,"wglCreateContext" | |
50 | ,"wglCreateLayerContext" | |
51 | ,"wglDeleteContext" | |
52 | ,"wglGetCurrentContext" | |
53 | ,"wglGetCurrentDC" | |
54 | ,"wglGetProcAddress" | |
55 | ,"wglMakeCurrent" | |
56 | ,"wglShareLists" | |
57 | ,"wglUseFontBitmapsA" | |
58 | ,"wglUseFontBitmapsW" | |
59 | ,"wglUseFontBitmaps" | |
60 | ,"SwapBuffers" | |
61 | ,"wglUseFontOutlinesA" | |
62 | ,"wglUseFontOutlinesW" | |
63 | ,"wglUseFontOutlines" | |
64 | ,"wglDescribeLayerPlane" | |
65 | ,"wglSetLayerPaletteEntries" | |
66 | ,"wglGetLayerPaletteEntries" | |
67 | ,"wglRealizeLayerPalette" | |
68 | ,"wglSwapLayerBuffers" | |
69 | ,"wglSwapMultipleBuffers" | |
70 | ,"ChoosePixelFormat" | |
71 | ,"DescribePixelFormat" | |
72 | ,"GetEnhMetaFilePixelFormat" | |
73 | ,"GetPixelFormat" | |
74 | ,"SetPixelFormat" | |
75 | ]} | |
76 | ||
77 | if __name__ == '__main__': | |
78 | i = 1 | |
79 | while (i < len(sys.argv)): | |
80 | arg = sys.argv[i] | |
81 | i = i + 1 | |
82 | if (arg == '-noprotect'): | |
83 | print('Disabling inclusion protection in output headers', file=sys.stderr) | |
84 | protect = False | |
85 | elif (arg == '-registry'): | |
86 | regFilename = sys.argv[i] | |
87 | i = i+1 | |
88 | print('Using registry', regFilename, file=sys.stderr) | |
89 | elif (arg == '-outfile'): | |
90 | outFilename = sys.argv[i] | |
91 | i = i+1 | |
92 | elif (arg == '-preresolve'): | |
93 | preresolve=True | |
94 | elif (arg == '-wrapper'): | |
95 | wrapper=True | |
96 | elif (arg == '-shim'): | |
97 | shim=True | |
98 | elif (arg == '-thunk'): | |
99 | thunk=True | |
100 | elif (arg == '-thunkdefs'): | |
101 | thunkdefs=True | |
102 | elif (arg == '-staticwrappers'): | |
103 | staticwrappers=True | |
104 | elif (arg == '-prefix'): | |
105 | prefix = sys.argv[i] | |
106 | i = i+1 | |
107 | elif (arg == '-nodebug'): | |
108 | nodebug = True | |
109 | elif (arg[0:1] == '-'): | |
110 | print('Unrecognized argument:', arg, file=sys.stderr) | |
111 | exit(1) | |
112 | ||
113 | print('Generating', outFilename, file=sys.stderr) | |
114 | ||
115 | # Load & parse registry | |
116 | reg = Registry() | |
117 | tree = etree.parse(regFilename) | |
118 | reg.loadElementTree(tree) | |
119 | ||
120 | allVersions = '.*' | |
121 | ||
122 | genOpts = CGeneratorOptions( | |
123 | apiname = prefix, | |
124 | profile = 'compatibility', | |
125 | versions = allVersions, | |
126 | emitversions = allVersions, | |
127 | defaultExtensions = prefix, # Default extensions for GL | |
128 | protectFile = protect, | |
129 | protectFeature = protect, | |
130 | protectProto = protect, | |
131 | ) | |
132 | ||
133 | # create error/warning & diagnostic files | |
134 | if (errFilename): | |
135 | errWarn = open(errFilename,'w') | |
136 | else: | |
137 | errWarn = sys.stderr | |
138 | diag = open(diagFilename, 'w') | |
139 | ||
140 | class PreResolveOutputGenerator(OutputGenerator): | |
141 | def __init__(self, | |
142 | errFile = sys.stderr, | |
143 | warnFile = sys.stderr, | |
144 | diagFile = sys.stdout): | |
145 | OutputGenerator.__init__(self, errFile, warnFile, diagFile) | |
146 | self.wrappers={} | |
147 | def beginFile(self, genOpts): | |
148 | self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename) | |
149 | def endFile(self): | |
150 | self.outFile.write('\nvoid ' + prefix + 'ResolveExtensionProcs(void)\n{\n') | |
151 | for funcname in self.wrappers.keys(): | |
152 | self.outFile.write( ' PRERESOLVE(PFN' + funcname.upper() + 'PROC, "' + funcname + '");\n') | |
153 | self.outFile.write('}\n\n') | |
154 | def beginFeature(self, interface, emit): | |
155 | OutputGenerator.beginFeature(self, interface, emit) | |
156 | def endFeature(self): | |
157 | OutputGenerator.endFeature(self) | |
158 | def genType(self, typeinfo, name): | |
159 | OutputGenerator.genType(self, typeinfo, name) | |
160 | def genEnum(self, enuminfo, name): | |
161 | OutputGenerator.genEnum(self, enuminfo, name) | |
162 | def genCmd(self, cmd, name): | |
163 | OutputGenerator.genCmd(self, cmd, name) | |
164 | ||
165 | if name in WinGDI: | |
166 | return | |
167 | ||
168 | self.outFile.write('RESOLVE_DECL(PFN' + name.upper() + 'PROC);\n') | |
169 | self.wrappers[name]=1 | |
170 | ||
171 | class WrapperOutputGenerator(OutputGenerator): | |
172 | def __init__(self, | |
173 | errFile = sys.stderr, | |
174 | warnFile = sys.stderr, | |
175 | diagFile = sys.stdout): | |
176 | OutputGenerator.__init__(self, errFile, warnFile, diagFile) | |
177 | def beginFile(self, genOpts): | |
178 | self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename) | |
179 | def endFile(self): | |
180 | pass | |
181 | def beginFeature(self, interface, emit): | |
182 | OutputGenerator.beginFeature(self, interface, emit) | |
183 | self.OldVersion = self.featureName.startswith('GL_VERSION_1_0') or self.featureName.startswith('GL_VERSION_1_1') | |
184 | def endFeature(self): | |
185 | OutputGenerator.endFeature(self) | |
186 | def genType(self, typeinfo, name): | |
187 | OutputGenerator.genType(self, typeinfo, name) | |
188 | def genEnum(self, enuminfo, name): | |
189 | OutputGenerator.genEnum(self, enuminfo, name) | |
190 | def genCmd(self, cmd, name): | |
191 | OutputGenerator.genCmd(self, cmd, name) | |
192 | ||
193 | if name in WinGDI: | |
194 | return | |
195 | ||
196 | proto=noneStr(cmd.elem.find('proto')) | |
197 | rettype=noneStr(proto.text) | |
198 | if rettype.lower()!="void ": | |
199 | plist = ([t for t in proto.itertext()]) | |
200 | rettype = ''.join(plist[:-1]) | |
201 | rettype=rettype.strip() | |
202 | if staticwrappers: self.outFile.write("static ") | |
203 | self.outFile.write("%s %sWrapper("%(rettype, name)) | |
204 | params = cmd.elem.findall('param') | |
205 | plist=[] | |
206 | for param in params: | |
207 | paramlist = ([t for t in param.itertext()]) | |
208 | paramtype = ''.join(paramlist[:-1]) | |
209 | paramname = paramlist[-1] | |
210 | plist.append((paramtype, paramname)) | |
211 | Comma="" | |
212 | if len(plist): | |
213 | for ptype, pname in plist: | |
214 | self.outFile.write("%s%s%s_"%(Comma, ptype, pname)) | |
215 | Comma=", " | |
216 | else: | |
217 | self.outFile.write("void") | |
218 | ||
219 | self.outFile.write(")\n{\n") | |
220 | ||
221 | # for GL 1.0 and 1.1 functions, generate stdcall wrappers which call the function directly | |
222 | if self.OldVersion: | |
223 | if not nodebug: | |
224 | self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name)) | |
225 | self.outFile.write(" glWinDirectProcCalls++;\n") | |
226 | self.outFile.write("\n") | |
227 | ||
228 | if rettype.lower()=="void": | |
229 | self.outFile.write(" %s( "%(name)) | |
230 | else: | |
231 | self.outFile.write(" return %s( "%(name)) | |
232 | ||
233 | Comma="" | |
234 | for ptype, pname in plist: | |
235 | self.outFile.write("%s%s_"%(Comma, pname)) | |
236 | Comma=", " | |
237 | ||
238 | # for GL 1.2+ functions, generate stdcall wrappers which use wglGetProcAddress() | |
239 | else: | |
240 | if rettype.lower()=="void": | |
241 | self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name)) | |
242 | ||
243 | if not nodebug: | |
244 | self.outFile.write("\n") | |
245 | self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name)) | |
246 | self.outFile.write("\n") | |
247 | ||
248 | self.outFile.write(" RESOLVED_PROC(PFN%sPROC)( """%(name.upper())) | |
249 | else: | |
250 | self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", FALSE);\n'%(name.upper(), name)) | |
251 | ||
252 | if not nodebug: | |
253 | self.outFile.write("\n") | |
254 | self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name)) | |
255 | self.outFile.write("\n") | |
256 | ||
257 | self.outFile.write(" return RESOLVED_PROC(PFN%sPROC)("%(name.upper())) | |
258 | ||
259 | Comma="" | |
260 | for ptype, pname in plist: | |
261 | self.outFile.write("%s%s_"%(Comma, pname)) | |
262 | Comma=", " | |
263 | self.outFile.write(" );\n}\n\n") | |
264 | ||
265 | class ThunkOutputGenerator(OutputGenerator): | |
266 | def __init__(self, | |
267 | errFile = sys.stderr, | |
268 | warnFile = sys.stderr, | |
269 | diagFile = sys.stdout): | |
270 | OutputGenerator.__init__(self, errFile, warnFile, diagFile) | |
271 | def beginFile(self, genOpts): | |
272 | self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename) | |
273 | def endFile(self): | |
274 | pass | |
275 | def beginFeature(self, interface, emit): | |
276 | OutputGenerator.beginFeature(self, interface, emit) | |
277 | self.OldVersion = self.featureName.startswith('GL_VERSION_1_0') or self.featureName.startswith('GL_VERSION_1_1') | |
278 | def endFeature(self): | |
279 | OutputGenerator.endFeature(self) | |
280 | def genType(self, typeinfo, name): | |
281 | OutputGenerator.genType(self, typeinfo, name) | |
282 | def genEnum(self, enuminfo, name): | |
283 | OutputGenerator.genEnum(self, enuminfo, name) | |
284 | def genCmd(self, cmd, name): | |
285 | OutputGenerator.genCmd(self, cmd, name) | |
286 | ||
287 | proto=noneStr(cmd.elem.find('proto')) | |
288 | rettype=noneStr(proto.text) | |
289 | if rettype.lower()!="void ": | |
290 | plist = ([t for t in proto.itertext()]) | |
291 | rettype = ''.join(plist[:-1]) | |
292 | rettype=rettype.strip() | |
293 | self.outFile.write("%s %sWrapper("%(rettype, name)) | |
294 | params = cmd.elem.findall('param') | |
295 | plist=[] | |
296 | for param in params: | |
297 | paramlist = ([t for t in param.itertext()]) | |
298 | paramtype = ''.join(paramlist[:-1]) | |
299 | paramname = paramlist[-1] | |
300 | plist.append((paramtype, paramname)) | |
301 | Comma="" | |
302 | if len(plist): | |
303 | for ptype, pname in plist: | |
304 | self.outFile.write("%s%s%s_"%(Comma, ptype, pname)) | |
305 | Comma=", " | |
306 | else: | |
307 | self.outFile.write("void") | |
308 | ||
309 | self.outFile.write(")\n{\n") | |
310 | ||
311 | # for GL 1.0 and 1.1 functions, generate stdcall thunk wrappers which call the function directly | |
312 | if self.OldVersion: | |
313 | if rettype.lower()=="void": | |
314 | self.outFile.write(" %s( "%(name)) | |
315 | else: | |
316 | self.outFile.write(" return %s( "%(name)) | |
317 | ||
318 | Comma="" | |
319 | for ptype, pname in plist: | |
320 | self.outFile.write("%s%s_"%(Comma, pname)) | |
321 | Comma=", " | |
322 | ||
323 | # for GL 1.2+ functions, generate wrappers which use wglGetProcAddress() | |
324 | else: | |
325 | if rettype.lower()=="void": | |
326 | self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name)) | |
327 | self.outFile.write(" RESOLVED_PROC(PFN%sPROC)( """%(name.upper())) | |
328 | else: | |
329 | self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", FALSE);\n'%(name.upper(), name)) | |
330 | self.outFile.write(" return RESOLVED_PROC(PFN%sPROC)("%(name.upper())) | |
331 | ||
332 | Comma="" | |
333 | for ptype, pname in plist: | |
334 | self.outFile.write("%s%s_"%(Comma, pname)) | |
335 | Comma=", " | |
336 | self.outFile.write(" );\n}\n\n") | |
337 | ||
338 | class ThunkDefsOutputGenerator(OutputGenerator): | |
339 | def __init__(self, | |
340 | errFile = sys.stderr, | |
341 | warnFile = sys.stderr, | |
342 | diagFile = sys.stdout): | |
343 | OutputGenerator.__init__(self, errFile, warnFile, diagFile) | |
344 | def beginFile(self, genOpts): | |
345 | self.outFile.write("EXPORTS\n"); # this must be the first line for libtool to realize this is a .def file | |
346 | self.outFile.write('; Automatically generated from %s - DO NOT EDIT\n\n'%regFilename) | |
347 | def endFile(self): | |
348 | pass | |
349 | def beginFeature(self, interface, emit): | |
350 | OutputGenerator.beginFeature(self, interface, emit) | |
351 | def endFeature(self): | |
352 | OutputGenerator.endFeature(self) | |
353 | def genType(self, typeinfo, name): | |
354 | OutputGenerator.genType(self, typeinfo, name) | |
355 | def genEnum(self, enuminfo, name): | |
356 | OutputGenerator.genEnum(self, enuminfo, name) | |
357 | def genCmd(self, cmd, name): | |
358 | OutputGenerator.genCmd(self, cmd, name) | |
359 | ||
360 | # export the wrapper function with the name of the function it wraps | |
361 | self.outFile.write("%s = %sWrapper\n"%(name, name)) | |
362 | ||
363 | class ShimOutputGenerator(OutputGenerator): | |
364 | def __init__(self, | |
365 | errFile = sys.stderr, | |
366 | warnFile = sys.stderr, | |
367 | diagFile = sys.stdout): | |
368 | OutputGenerator.__init__(self, errFile, warnFile, diagFile) | |
369 | def beginFile(self, genOpts): | |
370 | self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename) | |
371 | def endFile(self): | |
372 | pass | |
373 | def beginFeature(self, interface, emit): | |
374 | OutputGenerator.beginFeature(self, interface, emit) | |
375 | self.OldVersion = self.featureName.startswith('GL_VERSION_1_0') or self.featureName.startswith('GL_VERSION_1_1') or self.featureName.startswith('GL_VERSION_1_2') or self.featureName.startswith('GL_ARB_imaging') or self.featureName.startswith('GL_ARB_multitexture') or self.featureName.startswith('GL_ARB_texture_compression') | |
376 | def endFeature(self): | |
377 | OutputGenerator.endFeature(self) | |
378 | def genType(self, typeinfo, name): | |
379 | OutputGenerator.genType(self, typeinfo, name) | |
380 | def genEnum(self, enuminfo, name): | |
381 | OutputGenerator.genEnum(self, enuminfo, name) | |
382 | def genCmd(self, cmd, name): | |
383 | OutputGenerator.genCmd(self, cmd, name) | |
384 | ||
385 | if not self.OldVersion: | |
386 | return | |
387 | ||
388 | # for GL functions which are in the ABI, generate a shim which calls the function via GetProcAddress | |
389 | proto=noneStr(cmd.elem.find('proto')) | |
390 | rettype=noneStr(proto.text) | |
391 | if rettype.lower()!="void ": | |
392 | plist = ([t for t in proto.itertext()]) | |
393 | rettype = ''.join(plist[:-1]) | |
394 | rettype=rettype.strip() | |
395 | self.outFile.write("%s %s("%(rettype, name)) | |
396 | params = cmd.elem.findall('param') | |
397 | plist=[] | |
398 | for param in params: | |
399 | paramlist = ([t for t in param.itertext()]) | |
400 | paramtype = ''.join(paramlist[:-1]) | |
401 | paramname = paramlist[-1] | |
402 | plist.append((paramtype, paramname)) | |
403 | Comma="" | |
404 | if len(plist): | |
405 | for ptype, pname in plist: | |
406 | self.outFile.write("%s%s%s_"%(Comma, ptype, pname)) | |
407 | Comma=", " | |
408 | else: | |
409 | self.outFile.write("void") | |
410 | ||
411 | self.outFile.write(")\n{\n") | |
412 | ||
413 | self.outFile.write(' typedef %s (* PFN%sPROC)(' % (rettype, name.upper())) | |
414 | ||
415 | if len(plist): | |
416 | Comma="" | |
417 | for ptype, pname in plist: | |
418 | self.outFile.write("%s %s %s_"%(Comma, ptype, pname)) | |
419 | Comma=", " | |
420 | else: | |
421 | self.outFile.write("void") | |
422 | ||
423 | self.outFile.write(');\n') | |
424 | ||
425 | if rettype.lower()=="void": | |
426 | self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name)) | |
427 | self.outFile.write(' RESOLVED_PROC(') | |
428 | else: | |
429 | self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", 0);\n'%(name.upper(), name)) | |
430 | self.outFile.write(' return RESOLVED_PROC(') | |
431 | ||
432 | Comma="" | |
433 | for ptype, pname in plist: | |
434 | self.outFile.write("%s%s_"%(Comma, pname)) | |
435 | Comma=", " | |
436 | ||
437 | self.outFile.write(" );\n}\n\n") | |
438 | ||
439 | def genHeaders(): | |
440 | outFile = open(outFilename,"w") | |
441 | ||
442 | if preresolve: | |
443 | gen = PreResolveOutputGenerator(errFile=errWarn, | |
444 | warnFile=errWarn, | |
445 | diagFile=diag) | |
446 | gen.outFile=outFile | |
447 | reg.setGenerator(gen) | |
448 | reg.apiGen(genOpts) | |
449 | ||
450 | if wrapper: | |
451 | gen = WrapperOutputGenerator(errFile=errWarn, | |
452 | warnFile=errWarn, | |
453 | diagFile=diag) | |
454 | gen.outFile=outFile | |
455 | reg.setGenerator(gen) | |
456 | reg.apiGen(genOpts) | |
457 | ||
458 | if shim: | |
459 | gen = ShimOutputGenerator(errFile=errWarn, | |
460 | warnFile=errWarn, | |
461 | diagFile=diag) | |
462 | gen.outFile=outFile | |
463 | reg.setGenerator(gen) | |
464 | reg.apiGen(genOpts) | |
465 | ||
466 | if thunk: | |
467 | gen = ThunkOutputGenerator(errFile=errWarn, | |
468 | warnFile=errWarn, | |
469 | diagFile=diag) | |
470 | gen.outFile=outFile | |
471 | reg.setGenerator(gen) | |
472 | reg.apiGen(genOpts) | |
473 | ||
474 | ||
475 | if thunkdefs: | |
476 | gen = ThunkDefsOutputGenerator(errFile=errWarn, | |
477 | warnFile=errWarn, | |
478 | diagFile=diag) | |
479 | gen.outFile=outFile | |
480 | reg.setGenerator(gen) | |
481 | reg.apiGen(genOpts) | |
482 | ||
483 | outFile.close() | |
484 | ||
485 | genHeaders() |