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 27import sys, time, pdb, string, cProfile 28from reg import * 29 30# Default input / log files 31errFilename = None 32diagFilename = 'diag.txt' 33regFilename = 'gl.xml' 34outFilename = 'gen_gl_wrappers.c' 35 36protect=True 37prefix="gl" 38preresolve=False 39wrapper=False 40shim=False 41thunk=False 42thunkdefs=False 43staticwrappers=False 44nodebug=False 45 46# list of WGL extension functions we use 47used_wgl_ext_fns = {key: 1 for key in [ 48 "wglSwapIntervalEXT", 49 "wglGetExtensionsStringARB", 50 "wglDestroyPbufferARB", 51 "wglGetPbufferDCARB", 52 "wglReleasePbufferDCARB", 53 "wglCreatePbufferARB", 54 "wglMakeContextCurrentARB", 55 "wglChoosePixelFormatARB", 56 "wglGetPixelFormatAttribivARB", 57 "wglGetPixelFormatAttribivARB" 58]} 59 60if __name__ == '__main__': 61 i = 1 62 while (i < len(sys.argv)): 63 arg = sys.argv[i] 64 i = i + 1 65 if (arg == '-noprotect'): 66 print('Disabling inclusion protection in output headers', file=sys.stderr) 67 protect = False 68 elif (arg == '-registry'): 69 regFilename = sys.argv[i] 70 i = i+1 71 print('Using registry', regFilename, file=sys.stderr) 72 elif (arg == '-outfile'): 73 outFilename = sys.argv[i] 74 i = i+1 75 elif (arg == '-preresolve'): 76 preresolve=True 77 elif (arg == '-wrapper'): 78 wrapper=True 79 elif (arg == '-shim'): 80 shim=True 81 elif (arg == '-thunk'): 82 thunk=True 83 elif (arg == '-thunkdefs'): 84 thunkdefs=True 85 elif (arg == '-staticwrappers'): 86 staticwrappers=True 87 elif (arg == '-prefix'): 88 prefix = sys.argv[i] 89 i = i+1 90 elif (arg == '-nodebug'): 91 nodebug = True 92 elif (arg[0:1] == '-'): 93 print('Unrecognized argument:', arg, file=sys.stderr) 94 exit(1) 95 96print('Generating', outFilename, file=sys.stderr) 97 98# Load & parse registry 99reg = Registry() 100tree = etree.parse(regFilename) 101reg.loadElementTree(tree) 102 103if shim: 104 versions = '1\.[012]' 105else: 106 versions = '.*' 107 108genOpts = CGeneratorOptions( 109 apiname = prefix, 110 profile = 'compatibility', 111 versions = versions, 112 emitversions = versions, 113 defaultExtensions = prefix, # Default extensions for GL 114 protectFile = protect, 115 protectFeature = protect, 116 protectProto = protect, 117 ) 118 119# create error/warning & diagnostic files 120if (errFilename): 121 errWarn = open(errFilename,'w') 122else: 123 errWarn = sys.stderr 124diag = open(diagFilename, 'w') 125 126def ParseCmdRettype(cmd): 127 proto=noneStr(cmd.elem.find('proto')) 128 rettype=noneStr(proto.text) 129 if rettype.lower()!="void ": 130 plist = ([t for t in proto.itertext()]) 131 rettype = ''.join(plist[:-1]) 132 rettype=rettype.strip() 133 return rettype 134 135def ParseCmdParams(cmd): 136 params = cmd.elem.findall('param') 137 plist=[] 138 for param in params: 139 # construct the formal parameter definition from ptype and name 140 # elements, also using any text found around these in the 141 # param element, in the order it appears in the document 142 paramtype = '' 143 # also extract the formal parameter name from the name element 144 paramname = '' 145 for t in param.iter(): 146 if t.tag == 'ptype' or t.tag == 'param': 147 paramtype = paramtype + noneStr(t.text) 148 if t.tag == 'name': 149 paramname = t.text + '_' 150 paramtype = paramtype + ' ' + paramname 151 if t.tail is not None: 152 paramtype = paramtype + t.tail.strip() 153 plist.append((paramtype, paramname)) 154 return plist 155 156class PreResolveOutputGenerator(OutputGenerator): 157 def __init__(self, 158 errFile = sys.stderr, 159 warnFile = sys.stderr, 160 diagFile = sys.stdout): 161 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 162 self.wrappers={} 163 def beginFile(self, genOpts): 164 self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename) 165 def endFile(self): 166 self.outFile.write('\nvoid ' + prefix + 'ResolveExtensionProcs(void)\n{\n') 167 for funcname in self.wrappers.keys(): 168 self.outFile.write( ' PRERESOLVE(PFN' + funcname.upper() + 'PROC, "' + funcname + '");\n') 169 self.outFile.write('}\n\n') 170 def beginFeature(self, interface, emit): 171 OutputGenerator.beginFeature(self, interface, emit) 172 def endFeature(self): 173 OutputGenerator.endFeature(self) 174 def genType(self, typeinfo, name): 175 OutputGenerator.genType(self, typeinfo, name) 176 def genEnum(self, enuminfo, name): 177 OutputGenerator.genEnum(self, enuminfo, name) 178 def genCmd(self, cmd, name): 179 OutputGenerator.genCmd(self, cmd, name) 180 181 if prefix == 'wgl' and not name in used_wgl_ext_fns: 182 return 183 184 self.outFile.write('RESOLVE_DECL(PFN' + name.upper() + 'PROC);\n') 185 self.wrappers[name]=1 186 187class WrapperOutputGenerator(OutputGenerator): 188 def __init__(self, 189 errFile = sys.stderr, 190 warnFile = sys.stderr, 191 diagFile = sys.stdout): 192 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 193 def beginFile(self, genOpts): 194 self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename) 195 def endFile(self): 196 pass 197 def beginFeature(self, interface, emit): 198 OutputGenerator.beginFeature(self, interface, emit) 199 self.OldVersion = self.featureName.startswith('GL_VERSION_1_0') or self.featureName.startswith('GL_VERSION_1_1') 200 def endFeature(self): 201 OutputGenerator.endFeature(self) 202 def genType(self, typeinfo, name): 203 OutputGenerator.genType(self, typeinfo, name) 204 def genEnum(self, enuminfo, name): 205 OutputGenerator.genEnum(self, enuminfo, name) 206 def genCmd(self, cmd, name): 207 OutputGenerator.genCmd(self, cmd, name) 208 209 if prefix == 'wgl' and not name in used_wgl_ext_fns: 210 return 211 212 rettype=ParseCmdRettype(cmd) 213 214 if staticwrappers: self.outFile.write("static ") 215 self.outFile.write("%s %sWrapper("%(rettype, name)) 216 plist=ParseCmdParams(cmd) 217 Comma="" 218 if len(plist): 219 for ptype, pname in plist: 220 self.outFile.write("%s%s"%(Comma, ptype)) 221 Comma=", " 222 else: 223 self.outFile.write("void") 224 225 self.outFile.write(")\n{\n") 226 227 # for GL 1.0 and 1.1 functions, generate stdcall wrappers which call the function directly 228 if self.OldVersion: 229 if not nodebug: 230 self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name)) 231 self.outFile.write(" glWinDirectProcCalls++;\n") 232 self.outFile.write("\n") 233 234 if rettype.lower()=="void": 235 self.outFile.write(" %s( "%(name)) 236 else: 237 self.outFile.write(" return %s( "%(name)) 238 239 Comma="" 240 for ptype, pname in plist: 241 self.outFile.write("%s%s"%(Comma, pname)) 242 Comma=", " 243 244 # for GL 1.2+ functions, generate stdcall wrappers which use wglGetProcAddress() 245 else: 246 if rettype.lower()=="void": 247 self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name)) 248 249 if not nodebug: 250 self.outFile.write("\n") 251 self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name)) 252 self.outFile.write("\n") 253 254 self.outFile.write(" RESOLVED_PROC(PFN%sPROC)( """%(name.upper())) 255 else: 256 self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", FALSE);\n'%(name.upper(), name)) 257 258 if not nodebug: 259 self.outFile.write("\n") 260 self.outFile.write(' if (glxWinDebugSettings.enable%scallTrace) ErrorF("%s\\n");\n'%(prefix.upper(), name)) 261 self.outFile.write("\n") 262 263 self.outFile.write(" return RESOLVED_PROC(PFN%sPROC)("%(name.upper())) 264 265 Comma="" 266 for ptype, pname in plist: 267 self.outFile.write("%s%s"%(Comma, pname)) 268 Comma=", " 269 self.outFile.write(" );\n}\n\n") 270 271class ThunkOutputGenerator(OutputGenerator): 272 def __init__(self, 273 errFile = sys.stderr, 274 warnFile = sys.stderr, 275 diagFile = sys.stdout): 276 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 277 def beginFile(self, genOpts): 278 self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename) 279 def endFile(self): 280 pass 281 def beginFeature(self, interface, emit): 282 OutputGenerator.beginFeature(self, interface, emit) 283 self.OldVersion = (self.featureName in ['GL_VERSION_1_0', 'GL_VERSION_1_1']) 284 def endFeature(self): 285 OutputGenerator.endFeature(self) 286 def genType(self, typeinfo, name): 287 OutputGenerator.genType(self, typeinfo, name) 288 def genEnum(self, enuminfo, name): 289 OutputGenerator.genEnum(self, enuminfo, name) 290 def genCmd(self, cmd, name): 291 OutputGenerator.genCmd(self, cmd, name) 292 293 rettype=ParseCmdRettype(cmd) 294 self.outFile.write("%s %sWrapper("%(rettype, name)) 295 plist=ParseCmdParams(cmd) 296 297 Comma="" 298 if len(plist): 299 for ptype, pname in plist: 300 self.outFile.write("%s%s"%(Comma, ptype)) 301 Comma=", " 302 else: 303 self.outFile.write("void") 304 305 self.outFile.write(")\n{\n") 306 307 # for GL 1.0 and 1.1 functions, generate stdcall thunk wrappers which call the function directly 308 if self.OldVersion: 309 if rettype.lower()=="void": 310 self.outFile.write(" %s( "%(name)) 311 else: 312 self.outFile.write(" return %s( "%(name)) 313 314 Comma="" 315 for ptype, pname in plist: 316 self.outFile.write("%s%s"%(Comma, pname)) 317 Comma=", " 318 319 # for GL 1.2+ functions, generate wrappers which use wglGetProcAddress() 320 else: 321 if rettype.lower()=="void": 322 self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name)) 323 self.outFile.write(" RESOLVED_PROC(PFN%sPROC)( """%(name.upper())) 324 else: 325 self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", FALSE);\n'%(name.upper(), name)) 326 self.outFile.write(" return RESOLVED_PROC(PFN%sPROC)("%(name.upper())) 327 328 Comma="" 329 for ptype, pname in plist: 330 self.outFile.write("%s%s"%(Comma, pname)) 331 Comma=", " 332 self.outFile.write(" );\n}\n\n") 333 334class ThunkDefsOutputGenerator(OutputGenerator): 335 def __init__(self, 336 errFile = sys.stderr, 337 warnFile = sys.stderr, 338 diagFile = sys.stdout): 339 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 340 def beginFile(self, genOpts): 341 self.outFile.write("EXPORTS\n"); # this must be the first line for libtool to realize this is a .def file 342 self.outFile.write('; Automatically generated from %s - DO NOT EDIT\n\n'%regFilename) 343 def endFile(self): 344 pass 345 def beginFeature(self, interface, emit): 346 OutputGenerator.beginFeature(self, interface, emit) 347 def endFeature(self): 348 OutputGenerator.endFeature(self) 349 def genType(self, typeinfo, name): 350 OutputGenerator.genType(self, typeinfo, name) 351 def genEnum(self, enuminfo, name): 352 OutputGenerator.genEnum(self, enuminfo, name) 353 def genCmd(self, cmd, name): 354 OutputGenerator.genCmd(self, cmd, name) 355 356 # export the wrapper function with the name of the function it wraps 357 self.outFile.write("%s = %sWrapper\n"%(name, name)) 358 359class ShimOutputGenerator(OutputGenerator): 360 def __init__(self, 361 errFile = sys.stderr, 362 warnFile = sys.stderr, 363 diagFile = sys.stdout): 364 OutputGenerator.__init__(self, errFile, warnFile, diagFile) 365 def beginFile(self, genOpts): 366 self.outFile.write('/* Automatically generated from %s - DO NOT EDIT */\n\n'%regFilename) 367 def endFile(self): 368 pass 369 def beginFeature(self, interface, emit): 370 OutputGenerator.beginFeature(self, interface, emit) 371 self.OldVersion = (self.featureName in ['GL_VERSION_1_0', 'GL_VERSION_1_1', 'GL_VERSION_1_2', 'GL_ARB_imaging', 'GL_ARB_multitexture', 'GL_ARB_texture_compression']) 372 def endFeature(self): 373 OutputGenerator.endFeature(self) 374 def genType(self, typeinfo, name): 375 OutputGenerator.genType(self, typeinfo, name) 376 def genEnum(self, enuminfo, name): 377 OutputGenerator.genEnum(self, enuminfo, name) 378 def genCmd(self, cmd, name): 379 OutputGenerator.genCmd(self, cmd, name) 380 381 if not self.OldVersion: 382 return 383 384 # for GL functions which are in the ABI, generate a shim which calls the function via GetProcAddress 385 rettype=ParseCmdRettype(cmd) 386 self.outFile.write("%s %s("%(rettype, name)) 387 plist=ParseCmdParams(cmd) 388 389 Comma="" 390 if len(plist): 391 for ptype, pname in plist: 392 self.outFile.write("%s%s"%(Comma, ptype)) 393 Comma=", " 394 else: 395 self.outFile.write("void") 396 397 self.outFile.write(")\n{\n") 398 399 self.outFile.write(' typedef %s (* PFN%sPROC)(' % (rettype, name.upper())) 400 401 if len(plist): 402 Comma="" 403 for ptype, pname in plist: 404 self.outFile.write("%s %s"%(Comma, ptype)) 405 Comma=", " 406 else: 407 self.outFile.write("void") 408 409 self.outFile.write(');\n') 410 411 if rettype.lower()=="void": 412 self.outFile.write(' RESOLVE(PFN%sPROC, "%s");\n'%(name.upper(), name)) 413 self.outFile.write(' RESOLVED_PROC(') 414 else: 415 self.outFile.write(' RESOLVE_RET(PFN%sPROC, "%s", 0);\n'%(name.upper(), name)) 416 self.outFile.write(' return RESOLVED_PROC(') 417 418 Comma="" 419 for ptype, pname in plist: 420 self.outFile.write("%s%s"%(Comma, pname)) 421 Comma=", " 422 423 self.outFile.write(" );\n}\n\n") 424 425def genHeaders(): 426 outFile = open(outFilename,"w") 427 428 if preresolve: 429 gen = PreResolveOutputGenerator(errFile=errWarn, 430 warnFile=errWarn, 431 diagFile=diag) 432 gen.outFile=outFile 433 reg.setGenerator(gen) 434 reg.apiGen(genOpts) 435 436 if wrapper: 437 gen = WrapperOutputGenerator(errFile=errWarn, 438 warnFile=errWarn, 439 diagFile=diag) 440 gen.outFile=outFile 441 reg.setGenerator(gen) 442 reg.apiGen(genOpts) 443 444 if shim: 445 gen = ShimOutputGenerator(errFile=errWarn, 446 warnFile=errWarn, 447 diagFile=diag) 448 gen.outFile=outFile 449 reg.setGenerator(gen) 450 reg.apiGen(genOpts) 451 452 if thunk: 453 gen = ThunkOutputGenerator(errFile=errWarn, 454 warnFile=errWarn, 455 diagFile=diag) 456 gen.outFile=outFile 457 reg.setGenerator(gen) 458 reg.apiGen(genOpts) 459 460 461 if thunkdefs: 462 gen = ThunkDefsOutputGenerator(errFile=errWarn, 463 warnFile=errWarn, 464 diagFile=diag) 465 gen.outFile=outFile 466 reg.setGenerator(gen) 467 reg.apiGen(genOpts) 468 469 outFile.close() 470 471genHeaders() 472