4f58590a42
Tested by naddy@, jsg@ & kettenis@
469 lines
17 KiB
Python
469 lines
17 KiB
Python
#!/usr/bin/python3
|
|
#
|
|
# python script to generate cdecl to stdcall wrappers for GL functions
|
|
# adapted from genheaders.py
|
|
#
|
|
# Copyright (c) 2013 The Khronos Group Inc.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
# copy of this software and/or associated documentation files (the
|
|
# "Materials"), to deal in the Materials without restriction, including
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
# distribute, sublicense, and/or sell copies of the Materials, and to
|
|
# permit persons to whom the Materials are furnished to do so, subject to
|
|
# the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included
|
|
# in all copies or substantial portions of the Materials.
|
|
#
|
|
# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
|
|
|
import sys, time, pdb, string, cProfile
|
|
from reg import *
|
|
|
|
# Default input / log files
|
|
errFilename = None
|
|
diagFilename = 'diag.txt'
|
|
regFilename = 'gl.xml'
|
|
outFilename = 'gen_gl_wrappers.c'
|
|
|
|
protect=True
|
|
prefix="gl"
|
|
preresolve=False
|
|
wrapper=False
|
|
shim=False
|
|
thunk=False
|
|
thunkdefs=False
|
|
staticwrappers=False
|
|
nodebug=False
|
|
|
|
# list of WGL extension functions we use
|
|
used_wgl_ext_fns = {key: 1 for key in [
|
|
"wglSwapIntervalEXT",
|
|
"wglGetExtensionsStringARB",
|
|
"wglDestroyPbufferARB",
|
|
"wglGetPbufferDCARB",
|
|
"wglReleasePbufferDCARB",
|
|
"wglCreatePbufferARB",
|
|
"wglMakeContextCurrentARB",
|
|
"wglChoosePixelFormatARB",
|
|
"wglGetPixelFormatAttribivARB",
|
|
"wglGetPixelFormatAttribivARB"
|
|
]}
|
|
|
|
if __name__ == '__main__':
|
|
i = 1
|
|
while (i < len(sys.argv)):
|
|
arg = sys.argv[i]
|
|
i = i + 1
|
|
if (arg == '-noprotect'):
|
|
print('Disabling inclusion protection in output headers', file=sys.stderr)
|
|
protect = False
|
|
elif (arg == '-registry'):
|
|
regFilename = sys.argv[i]
|
|
i = i+1
|
|
print('Using registry', regFilename, file=sys.stderr)
|
|
elif (arg == '-outfile'):
|
|
outFilename = sys.argv[i]
|
|
i = i+1
|
|
elif (arg == '-preresolve'):
|
|
preresolve=True
|
|
elif (arg == '-wrapper'):
|
|
wrapper=True
|
|
elif (arg == '-shim'):
|
|
shim=True
|
|
elif (arg == '-thunk'):
|
|
thunk=True
|
|
elif (arg == '-thunkdefs'):
|
|
thunkdefs=True
|
|
elif (arg == '-staticwrappers'):
|
|
staticwrappers=True
|
|
elif (arg == '-prefix'):
|
|
prefix = sys.argv[i]
|
|
i = i+1
|
|
elif (arg == '-nodebug'):
|
|
nodebug = True
|
|
elif (arg[0:1] == '-'):
|
|
print('Unrecognized argument:', arg, file=sys.stderr)
|
|
exit(1)
|
|
|
|
print('Generating', outFilename, file=sys.stderr)
|
|
|
|
# Load & parse registry
|
|
reg = Registry()
|
|
tree = etree.parse(regFilename)
|
|
reg.loadElementTree(tree)
|
|
|
|
allVersions = '.*'
|
|
|
|
genOpts = CGeneratorOptions(
|
|
apiname = prefix,
|
|
profile = 'compatibility',
|
|
versions = allVersions,
|
|
emitversions = allVersions,
|
|
defaultExtensions = prefix, # Default extensions for GL
|
|
protectFile = protect,
|
|
protectFeature = protect,
|
|
protectProto = protect,
|
|
)
|
|
|
|
# create error/warning & diagnostic files
|
|
if (errFilename):
|
|
errWarn = open(errFilename,'w')
|
|
else:
|
|
errWarn = sys.stderr
|
|
diag = open(diagFilename, 'w')
|
|
|
|
class PreResolveOutputGenerator(OutputGenerator):
|
|
def __init__(self,
|
|
errFile = sys.stderr,
|
|
warnFile = sys.stderr,
|
|
diagFile = sys.stdout):
|
|
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
|
self.wrappers={}
|
|
def beginFile(self, genOpts):
|
|
self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename)
|
|
def endFile(self):
|
|
self.outFile.write('\nvoid ' + prefix + 'ResolveExtensionProcs(void)\n{\n')
|
|
for funcname in self.wrappers.keys():
|
|
self.outFile.write( ' PRERESOLVE(PFN' + funcname.upper() + 'PROC, "' + funcname + '");\n')
|
|
self.outFile.write('}\n\n')
|
|
def beginFeature(self, interface, emit):
|
|
OutputGenerator.beginFeature(self, interface, emit)
|
|
def endFeature(self):
|
|
OutputGenerator.endFeature(self)
|
|
def genType(self, typeinfo, name):
|
|
OutputGenerator.genType(self, typeinfo, name)
|
|
def genEnum(self, enuminfo, name):
|
|
OutputGenerator.genEnum(self, enuminfo, name)
|
|
def genCmd(self, cmd, name):
|
|
OutputGenerator.genCmd(self, cmd, name)
|
|
|
|
if prefix == 'wgl' and not name in used_wgl_ext_fns:
|
|
return
|
|
|
|
self.outFile.write('RESOLVE_DECL(PFN' + name.upper() + 'PROC);\n')
|
|
self.wrappers[name]=1
|
|
|
|
class WrapperOutputGenerator(OutputGenerator):
|
|
def __init__(self,
|
|
errFile = sys.stderr,
|
|
warnFile = sys.stderr,
|
|
diagFile = sys.stdout):
|
|
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
|
def beginFile(self, genOpts):
|
|
self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename)
|
|
def endFile(self):
|
|
pass
|
|
def beginFeature(self, interface, emit):
|
|
OutputGenerator.beginFeature(self, interface, emit)
|
|
self.OldVersion = self.featureName.startswith('GL_VERSION_1_0') or self.featureName.startswith('GL_VERSION_1_1')
|
|
def endFeature(self):
|
|
OutputGenerator.endFeature(self)
|
|
def genType(self, typeinfo, name):
|
|
OutputGenerator.genType(self, typeinfo, name)
|
|
def genEnum(self, enuminfo, name):
|
|
OutputGenerator.genEnum(self, enuminfo, name)
|
|
def genCmd(self, cmd, name):
|
|
OutputGenerator.genCmd(self, cmd, name)
|
|
|
|
if prefix == 'wgl' and not name in used_wgl_ext_fns:
|
|
return
|
|
|
|
proto=noneStr(cmd.elem.find('proto'))
|
|
rettype=noneStr(proto.text)
|
|
if rettype.lower()!="void ":
|
|
plist = ([t for t in proto.itertext()])
|
|
rettype = ''.join(plist[:-1])
|
|
rettype=rettype.strip()
|
|
if staticwrappers: self.outFile.write("static ")
|
|
self.outFile.write("%s %sWrapper("%(rettype, name))
|
|
params = cmd.elem.findall('param')
|
|
plist=[]
|
|
for param in params:
|
|
paramlist = ([t for t in param.itertext()])
|
|
paramtype = ''.join(paramlist[:-1])
|
|
paramname = paramlist[-1]
|
|
plist.append((paramtype, paramname))
|
|
Comma=""
|
|
if len(plist):
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s%s%s_"%(Comma, ptype, pname))
|
|
Comma=", "
|
|
else:
|
|
self.outFile.write("void")
|
|
|
|
self.outFile.write(")\n{\n")
|
|
|
|
# for GL 1.0 and 1.1 functions, generate stdcall wrappers which call the function directly
|
|
if self.OldVersion:
|
|
if not nodebug:
|
|
self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name))
|
|
self.outFile.write(" glWinDirectProcCalls++;\n")
|
|
self.outFile.write("\n")
|
|
|
|
if rettype.lower()=="void":
|
|
self.outFile.write(" %s( "%(name))
|
|
else:
|
|
self.outFile.write(" return %s( "%(name))
|
|
|
|
Comma=""
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s%s_"%(Comma, pname))
|
|
Comma=", "
|
|
|
|
# for GL 1.2+ functions, generate stdcall wrappers which use wglGetProcAddress()
|
|
else:
|
|
if rettype.lower()=="void":
|
|
self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name))
|
|
|
|
if not nodebug:
|
|
self.outFile.write("\n")
|
|
self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name))
|
|
self.outFile.write("\n")
|
|
|
|
self.outFile.write(" RESOLVED_PROC(PFN%sPROC)( """%(name.upper()))
|
|
else:
|
|
self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", FALSE);\n'%(name.upper(), name))
|
|
|
|
if not nodebug:
|
|
self.outFile.write("\n")
|
|
self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name))
|
|
self.outFile.write("\n")
|
|
|
|
self.outFile.write(" return RESOLVED_PROC(PFN%sPROC)("%(name.upper()))
|
|
|
|
Comma=""
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s%s_"%(Comma, pname))
|
|
Comma=", "
|
|
self.outFile.write(" );\n}\n\n")
|
|
|
|
class ThunkOutputGenerator(OutputGenerator):
|
|
def __init__(self,
|
|
errFile = sys.stderr,
|
|
warnFile = sys.stderr,
|
|
diagFile = sys.stdout):
|
|
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
|
def beginFile(self, genOpts):
|
|
self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename)
|
|
def endFile(self):
|
|
pass
|
|
def beginFeature(self, interface, emit):
|
|
OutputGenerator.beginFeature(self, interface, emit)
|
|
self.OldVersion = self.featureName.startswith('GL_VERSION_1_0') or self.featureName.startswith('GL_VERSION_1_1')
|
|
def endFeature(self):
|
|
OutputGenerator.endFeature(self)
|
|
def genType(self, typeinfo, name):
|
|
OutputGenerator.genType(self, typeinfo, name)
|
|
def genEnum(self, enuminfo, name):
|
|
OutputGenerator.genEnum(self, enuminfo, name)
|
|
def genCmd(self, cmd, name):
|
|
OutputGenerator.genCmd(self, cmd, name)
|
|
|
|
proto=noneStr(cmd.elem.find('proto'))
|
|
rettype=noneStr(proto.text)
|
|
if rettype.lower()!="void ":
|
|
plist = ([t for t in proto.itertext()])
|
|
rettype = ''.join(plist[:-1])
|
|
rettype=rettype.strip()
|
|
self.outFile.write("%s %sWrapper("%(rettype, name))
|
|
params = cmd.elem.findall('param')
|
|
plist=[]
|
|
for param in params:
|
|
paramlist = ([t for t in param.itertext()])
|
|
paramtype = ''.join(paramlist[:-1])
|
|
paramname = paramlist[-1]
|
|
plist.append((paramtype, paramname))
|
|
Comma=""
|
|
if len(plist):
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s%s%s_"%(Comma, ptype, pname))
|
|
Comma=", "
|
|
else:
|
|
self.outFile.write("void")
|
|
|
|
self.outFile.write(")\n{\n")
|
|
|
|
# for GL 1.0 and 1.1 functions, generate stdcall thunk wrappers which call the function directly
|
|
if self.OldVersion:
|
|
if rettype.lower()=="void":
|
|
self.outFile.write(" %s( "%(name))
|
|
else:
|
|
self.outFile.write(" return %s( "%(name))
|
|
|
|
Comma=""
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s%s_"%(Comma, pname))
|
|
Comma=", "
|
|
|
|
# for GL 1.2+ functions, generate wrappers which use wglGetProcAddress()
|
|
else:
|
|
if rettype.lower()=="void":
|
|
self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name))
|
|
self.outFile.write(" RESOLVED_PROC(PFN%sPROC)( """%(name.upper()))
|
|
else:
|
|
self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", FALSE);\n'%(name.upper(), name))
|
|
self.outFile.write(" return RESOLVED_PROC(PFN%sPROC)("%(name.upper()))
|
|
|
|
Comma=""
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s%s_"%(Comma, pname))
|
|
Comma=", "
|
|
self.outFile.write(" );\n}\n\n")
|
|
|
|
class ThunkDefsOutputGenerator(OutputGenerator):
|
|
def __init__(self,
|
|
errFile = sys.stderr,
|
|
warnFile = sys.stderr,
|
|
diagFile = sys.stdout):
|
|
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
|
def beginFile(self, genOpts):
|
|
self.outFile.write("EXPORTS\n"); # this must be the first line for libtool to realize this is a .def file
|
|
self.outFile.write('; Automatically generated from %s - DO NOT EDIT\n\n'%regFilename)
|
|
def endFile(self):
|
|
pass
|
|
def beginFeature(self, interface, emit):
|
|
OutputGenerator.beginFeature(self, interface, emit)
|
|
def endFeature(self):
|
|
OutputGenerator.endFeature(self)
|
|
def genType(self, typeinfo, name):
|
|
OutputGenerator.genType(self, typeinfo, name)
|
|
def genEnum(self, enuminfo, name):
|
|
OutputGenerator.genEnum(self, enuminfo, name)
|
|
def genCmd(self, cmd, name):
|
|
OutputGenerator.genCmd(self, cmd, name)
|
|
|
|
# export the wrapper function with the name of the function it wraps
|
|
self.outFile.write("%s = %sWrapper\n"%(name, name))
|
|
|
|
class ShimOutputGenerator(OutputGenerator):
|
|
def __init__(self,
|
|
errFile = sys.stderr,
|
|
warnFile = sys.stderr,
|
|
diagFile = sys.stdout):
|
|
OutputGenerator.__init__(self, errFile, warnFile, diagFile)
|
|
def beginFile(self, genOpts):
|
|
self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename)
|
|
def endFile(self):
|
|
pass
|
|
def beginFeature(self, interface, emit):
|
|
OutputGenerator.beginFeature(self, interface, emit)
|
|
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')
|
|
def endFeature(self):
|
|
OutputGenerator.endFeature(self)
|
|
def genType(self, typeinfo, name):
|
|
OutputGenerator.genType(self, typeinfo, name)
|
|
def genEnum(self, enuminfo, name):
|
|
OutputGenerator.genEnum(self, enuminfo, name)
|
|
def genCmd(self, cmd, name):
|
|
OutputGenerator.genCmd(self, cmd, name)
|
|
|
|
if not self.OldVersion:
|
|
return
|
|
|
|
# for GL functions which are in the ABI, generate a shim which calls the function via GetProcAddress
|
|
proto=noneStr(cmd.elem.find('proto'))
|
|
rettype=noneStr(proto.text)
|
|
if rettype.lower()!="void ":
|
|
plist = ([t for t in proto.itertext()])
|
|
rettype = ''.join(plist[:-1])
|
|
rettype=rettype.strip()
|
|
self.outFile.write("%s %s("%(rettype, name))
|
|
params = cmd.elem.findall('param')
|
|
plist=[]
|
|
for param in params:
|
|
paramlist = ([t for t in param.itertext()])
|
|
paramtype = ''.join(paramlist[:-1])
|
|
paramname = paramlist[-1]
|
|
plist.append((paramtype, paramname))
|
|
Comma=""
|
|
if len(plist):
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s%s%s_"%(Comma, ptype, pname))
|
|
Comma=", "
|
|
else:
|
|
self.outFile.write("void")
|
|
|
|
self.outFile.write(")\n{\n")
|
|
|
|
self.outFile.write(' typedef %s (* PFN%sPROC)(' % (rettype, name.upper()))
|
|
|
|
if len(plist):
|
|
Comma=""
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s %s %s_"%(Comma, ptype, pname))
|
|
Comma=", "
|
|
else:
|
|
self.outFile.write("void")
|
|
|
|
self.outFile.write(');\n')
|
|
|
|
if rettype.lower()=="void":
|
|
self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name))
|
|
self.outFile.write(' RESOLVED_PROC(')
|
|
else:
|
|
self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", 0);\n'%(name.upper(), name))
|
|
self.outFile.write(' return RESOLVED_PROC(')
|
|
|
|
Comma=""
|
|
for ptype, pname in plist:
|
|
self.outFile.write("%s%s_"%(Comma, pname))
|
|
Comma=", "
|
|
|
|
self.outFile.write(" );\n}\n\n")
|
|
|
|
def genHeaders():
|
|
outFile = open(outFilename,"w")
|
|
|
|
if preresolve:
|
|
gen = PreResolveOutputGenerator(errFile=errWarn,
|
|
warnFile=errWarn,
|
|
diagFile=diag)
|
|
gen.outFile=outFile
|
|
reg.setGenerator(gen)
|
|
reg.apiGen(genOpts)
|
|
|
|
if wrapper:
|
|
gen = WrapperOutputGenerator(errFile=errWarn,
|
|
warnFile=errWarn,
|
|
diagFile=diag)
|
|
gen.outFile=outFile
|
|
reg.setGenerator(gen)
|
|
reg.apiGen(genOpts)
|
|
|
|
if shim:
|
|
gen = ShimOutputGenerator(errFile=errWarn,
|
|
warnFile=errWarn,
|
|
diagFile=diag)
|
|
gen.outFile=outFile
|
|
reg.setGenerator(gen)
|
|
reg.apiGen(genOpts)
|
|
|
|
if thunk:
|
|
gen = ThunkOutputGenerator(errFile=errWarn,
|
|
warnFile=errWarn,
|
|
diagFile=diag)
|
|
gen.outFile=outFile
|
|
reg.setGenerator(gen)
|
|
reg.apiGen(genOpts)
|
|
|
|
|
|
if thunkdefs:
|
|
gen = ThunkDefsOutputGenerator(errFile=errWarn,
|
|
warnFile=errWarn,
|
|
diagFile=diag)
|
|
gen.outFile=outFile
|
|
reg.setGenerator(gen)
|
|
reg.apiGen(genOpts)
|
|
|
|
outFile.close()
|
|
|
|
genHeaders()
|