3 # python script to generate cdecl to stdcall wrappers for GL functions
4 # adapted from genheaders.py
6 # Copyright (c) 2013 The Khronos Group Inc.
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:
16 # The above copyright notice and this permission notice shall be included
17 # in all copies or substantial portions of the Materials.
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.
27 import sys
, time
, pdb
, string
, cProfile
30 # Default input / log files
32 diagFilename
= 'diag.txt'
33 regFilename
= 'gl.xml'
34 outFilename
= 'gen_gl_wrappers.c'
47 WinGDI
={key
: 1 for key
in [
50 ,"wglCreateLayerContext"
52 ,"wglGetCurrentContext"
61 ,"wglUseFontOutlinesA"
62 ,"wglUseFontOutlinesW"
64 ,"wglDescribeLayerPlane"
65 ,"wglSetLayerPaletteEntries"
66 ,"wglGetLayerPaletteEntries"
67 ,"wglRealizeLayerPalette"
68 ,"wglSwapLayerBuffers"
69 ,"wglSwapMultipleBuffers"
71 ,"DescribePixelFormat"
72 ,"GetEnhMetaFilePixelFormat"
77 if __name__
== '__main__':
79 while (i
< len(sys
.argv
)):
82 if (arg
== '-noprotect'):
83 print('Disabling inclusion protection in output headers', file=sys
.stderr
)
85 elif (arg
== '-registry'):
86 regFilename
= sys
.argv
[i
]
88 print('Using registry', regFilename
, file=sys
.stderr
)
89 elif (arg
== '-outfile'):
90 outFilename
= sys
.argv
[i
]
92 elif (arg
== '-preresolve'):
94 elif (arg
== '-wrapper'):
96 elif (arg
== '-shim'):
98 elif (arg
== '-thunk'):
100 elif (arg
== '-thunkdefs'):
102 elif (arg
== '-staticwrappers'):
104 elif (arg
== '-prefix'):
107 elif (arg
== '-nodebug'):
109 elif (arg
[0:1] == '-'):
110 print('Unrecognized argument:', arg
, file=sys
.stderr
)
113 print('Generating', outFilename
, file=sys
.stderr
)
115 # Load & parse registry
117 tree
= etree
.parse(regFilename
)
118 reg
.loadElementTree(tree
)
122 genOpts
= CGeneratorOptions(
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
,
133 # create error/warning & diagnostic files
135 errWarn
= open(errFilename
,'w')
138 diag
= open(diagFilename
, 'w')
140 class PreResolveOutputGenerator(OutputGenerator
):
142 errFile
= sys
.stderr
,
143 warnFile
= sys
.stderr
,
144 diagFile
= sys
.stdout
):
145 OutputGenerator
.__init
__(self
, errFile
, warnFile
, diagFile
)
147 def beginFile(self
, genOpts
):
148 self
.outFile
.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename
)
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
)
168 self
.outFile
.write('RESOLVE_DECL(PFN' + name
.upper() + 'PROC);\n')
169 self
.wrappers
[name
]=1
171 class WrapperOutputGenerator(OutputGenerator
):
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
)
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
)
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')
207 paramlist
= ([t
for t
in param
.itertext()])
208 paramtype
= ''.join(paramlist
[:-1])
209 paramname
= paramlist
[-1]
210 plist
.append((paramtype
, paramname
))
213 for ptype
, pname
in plist
:
214 self
.outFile
.write("%s%s%s_"%(Comma
, ptype
, pname
))
217 self
.outFile
.write("void")
219 self
.outFile
.write(")\n{\n")
221 # for GL 1.0 and 1.1 functions, generate stdcall wrappers which call the function directly
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")
228 if rettype
.lower()=="void":
229 self
.outFile
.write(" %s( "%(name))
231 self
.outFile
.write(" return %s( "%(name))
234 for ptype
, pname
in plist
:
235 self
.outFile
.write("%s%s_"%(Comma
, pname
))
238 # for GL 1.2+ functions, generate stdcall wrappers which use wglGetProcAddress()
240 if rettype
.lower()=="void":
241 self
.outFile
.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name
.upper(), name
))
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")
248 self
.outFile
.write(" RESOLVED_PROC(PFN%sPROC)( """%(name.upper()))
250 self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", FALSE);\n'%(name.upper(), name))
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")
257 self.outFile.write(" return RESOLVED_PROC(PFN
%sPROC
)("%(name.upper()))
260 for ptype, pname in plist:
261 self.outFile.write("%s%s_"%(Comma, pname))
263 self.outFile.write(" );\n}\n\n")
265 class ThunkOutputGenerator(OutputGenerator):
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)
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)
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')
297 paramlist = ([t for t in param.itertext()])
298 paramtype = ''.join(paramlist[:-1])
299 paramname = paramlist[-1]
300 plist.append((paramtype, paramname))
303 for ptype, pname in plist:
304 self.outFile.write("%s%s%s_"%(Comma, ptype, pname))
307 self.outFile.write("void
")
309 self.outFile.write(")\n{\n")
311 # for GL 1.0 and 1.1 functions, generate stdcall thunk wrappers which call the function directly
313 if rettype.lower()=="void
":
314 self.outFile.write(" %s( "%(name))
316 self.outFile.write(" return %s( "%(name))
319 for ptype, pname in plist:
320 self.outFile.write("%s%s_"%(Comma, pname))
323 # for GL 1.2+ functions, generate wrappers which use wglGetProcAddress()
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()))
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()))
333 for ptype, pname in plist:
334 self.outFile.write("%s%s_"%(Comma, pname))
336 self.outFile.write(" );\n}\n\n")
338 class ThunkDefsOutputGenerator(OutputGenerator):
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)
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)
360 # export the wrapper function with the name of the function it wraps
361 self.outFile.write("%s = %sWrapper\n"%(name, name))
363 class ShimOutputGenerator(OutputGenerator):
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)
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)
385 if not self.OldVersion:
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')
399 paramlist = ([t for t in param.itertext()])
400 paramtype = ''.join(paramlist[:-1])
401 paramname = paramlist[-1]
402 plist.append((paramtype, paramname))
405 for ptype, pname in plist:
406 self.outFile.write("%s%s%s_"%(Comma, ptype, pname))
409 self.outFile.write("void")
411 self.outFile.write(")\n{\n")
413 self.outFile.write(' typedef %s (* PFN%sPROC)(' % (rettype, name.upper()))
417 for ptype, pname in plist:
418 self.outFile.write("%s %s %s_"%(Comma, ptype, pname))
421 self.outFile.write("void")
423 self.outFile.write(');\n')
425 if rettype.lower()=="void":
426 self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name))
427 self.outFile.write(' RESOLVED_PROC(')
429 self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", 0);\n'%(name.upper(), name))
430 self.outFile.write(' return RESOLVED_PROC(')
433 for ptype, pname in plist:
434 self.outFile.write("%s%s_"%(Comma, pname))
437 self.outFile.write(" );\n}\n\n")
440 outFile = open(outFilename,"w")
443 gen = PreResolveOutputGenerator(errFile=errWarn,
447 reg.setGenerator(gen)
451 gen = WrapperOutputGenerator(errFile=errWarn,
455 reg.setGenerator(gen)
459 gen = ShimOutputGenerator(errFile=errWarn,
463 reg.setGenerator(gen)
467 gen = ThunkOutputGenerator(errFile=errWarn,
471 reg.setGenerator(gen)
476 gen = ThunkDefsOutputGenerator(errFile=errWarn,
480 reg.setGenerator(gen)